codeforces 925 c big secret

题意:

给你n个数,b[1],b[2],b[3].......,让你重新排列,使a[i]的值递增

a[i]和b的关系:

a[i] = b[1]^b[2]^b[3]^....^b[i];

首先说异或  因为是递增,所以1^0  0^0  1^1都不满足条件

只有0^1满足条件    

1^0 == 1   相当于没有增长

0^1 == 1  这才相当于增长了1

再看   a=00 01 01 10

   b=00 10 11 10

这两个二进制数a,b进行异或

对于第一位  大家都等于0  异或出来相当于没变

第二位  大家都等于1  异或出来相当于少1

第三位。。。。。

第四位 a第四位等于0   b第四位等于1  两个数异或  相当于b的这一位没有改变

第五位 a第五位等于1    b第五位等于0 两个数异或  b的这一位变成1 

所以只要选择a的最高位等于1     b的这一位等于0的情况进行异或

但是为什么要选择最高位:

因为只要最高位进行了增加    比他低的位无论加1还是减1都不会影响异或后的大小关系

可惜就是这样我也没想出来,想到了0和1的异或关系和一位一位去算

但是没做出来   可惜了

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const long long maxn = 2e5+5;
const long long N = (long long)1<<59;
long long a[maxn];
long long b[maxn];
vector<long long> bit[68];
int main()
{
    long long n,i,j,k;
    long long x;
    scanf("%lld",&n);
    for(i=0;i<n;++i)
    {
        scanf("%lld",b+i);
        x = 1;
        for(j = 59;j>=0;--j)
        {
            if((x<<j)&b[i])
            {
                bit[j].push_back(b[i]);
                break;
            }
        }
    }
    x = 0;
    for(i=0;i<n;++i)
    {
        bool flag = false;
        for(j=0;j<60;++j)
        {
            if(((x&((long long)1<<j)) == 0) && bit[j].size())
            {
                a[i] = bit[j][bit[j].size()-1];
                x ^= bit[j][bit[j].size()-1];
                bit[j].pop_back();
                flag = true;
                break;
            }
        }
        if(!flag)
        {
            printf("No
");
            return 0;
        }
    }
    printf("Yes
");
    for(i=0;i<n;++i)
        printf("%lld ",a[i]);
}
原文地址:https://www.cnblogs.com/mltang/p/9037622.html