codeforces 460D Little Victor and Set(构造、枚举)

最近的CF几乎都没打,感觉挺水的一个题,不过自己仿佛状态不在,看题解才知道做法。

输入l, r, k (1 ≤ l ≤ r ≤ 1012; 1 ≤ k ≤ min(106, r - l + 1)).

从[l,r]选至多k个数使得选出的数的异或值最小,输出最小异或值和方案。

分类讨论,首先如果r-l+1<=4,枚举集合解决之。

先面讨论r-l+1>=5的情况:

此时有至少5个数可以选择,故至少有连续的4个数满足2x,2x+1,2x+2,2x+3。

k==1时显然方案为{l}。k==2时,显然方案为{2x,2x+1}。k>=4时,显然方案为{2x,2x+1,2x+2,2x+3}。

k==3时再另外考虑:

首先,异或值至多为1(参考k==2)

我们现在来找异或值可否为0。先假设可以,则显然是选3个数。不妨设x>y>z。

111...1111

111...1110

000...0001

显然x,y,z前半部分必定是如上这样的,但由于我们要使得x,y,z尽量靠近,所以x,y,z前半部分必然是如下

11

10

01

之后,每添加一位,有可能是yi=zi=1,xi=0或xi=zi=1,yi=0或xi=yi=1,zi=0。

由于要x,y,z尽量靠近,所以显然采取yi=zi=1,zi=0。

所以x,y,z的二进制形式如下

110...0

101...1

011...1

至此,问题大致解决,剩下的就是些细节问题,问题不大。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;

#define ll long long

int cnt(int i){
    int ret=0;
    while(i) i-=i&(-i), ++ret;
    return ret;
}
int main(){
    ll l,r;
    int k;
    while(~scanf("%I64d%I64d%d",&l,&r,&k)){
        if(r-l+1<5){
            int n=r-l+1;
            ll ansxor=1ll<<60;
            vector<ll>val;
            for(int i=1;i<(1<<n);++i){
                ll xx=0;
                for(int j=0;j<n;++j)
                    if(i&(1<<j)) xx^=l+j;
                if(xx<ansxor && cnt(i)<=k){
                    ansxor=xx;
                    val.clear();
                    for(int j=0;j<n;++j) if(i&(1<<j)) val.push_back(l+j);
                }
            }
            printf("%I64d
",ansxor);
            printf("%d
",val.size());
            for(int i=0;i<val.size();++i) printf("%I64d%c",val[i],i==val.size()-1?'
':' ');
        }
        else if(r-l+1>=5){
            if(k==1){printf("%I64d
1
%I64d
",l,l);continue;}
            if(k==2){
                if(l&1) l++;
                puts("1");
                puts("2");
                printf("%I64d %I64d
",l,l+1);
            }
            else if(k>=4){
                if(l&1) l++;
                puts("0");
                puts("4");
                printf("%I64d %I64d %I64d %I64d
",l,l+1,l+2,l+3);
            }
            else if(k==3){
                ll x=-1,y,z;
                for(ll i=3;i<=r;i=i<<1){
                    if((i^(i-1))>=l){
                        x=i;
                        y=i - 1;
                        z=i^(i-1);
                        break;
                    }
                }
                if(x!=-1){
                    puts("0");
                    puts("3");
                    printf("%I64d %I64d %I64d
",x,y,z);
                }
                else {
                    if(l&1) l++;
                    puts("1");
                    puts("2");
                    printf("%I64d %I64d
",l,l+1);
                }
            }
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/nextbin/p/3930148.html