思路:
,则有,也就是说只要知道A1就可以求任意A。由于A是升序排列,所以对于任意,二进制所包含1的最高位第k位来说,表明与第k位相反,要大一些,所以它的第k位为1,的第k位为0,例如Bi=10对应的二进制数为1010,最高位1就是第3位,所以就能确定Ai+1的第三位为1,Ai的第三位为0;类似这样操作,就能找出A中很多确定的值,不确定的位根据k去判断。为了方便计算,我们的是要去预处理b的前缀异或,然后解出a1就能得出,为了找到a1的某些确定值,我们同样的去找bi最高位1为第k位,然后记录s[i]的第k位的值,因为要使a[i+1]的第k位为1,由于,那么只要记录下si,就能根据a1的值得到ai+1的第k位为1;而且若出现多次相同的最高位1,前缀异或值必须相等,否则矛盾输出-1。
对于未知位,可以把这些未知位紧贴看成一个二进制数,使此二进制的值为k-1,就是所求字典序第k小的值。例如k=3,a1=1x1x0,x代表未知,将两个未知位紧贴xx,让它的值为2也就是二进制表示10,就是字典序第三小的值,所以a1=11100。
#include<bits/stdc++.h>
using namespace std;
int s[1000005];
int a[1000005];//第i位上是否为1
int a1[1000005];//第i位上为1的前i-1位异或和
int main()
{int T;cin>>T;int h=0;//最高位 while(T--){int n,k;cin>>n>>k;memset(a,0,sizeof(a));memset(a1,0,sizeof(a1));int flag=1;int a2=30;//所包含的最高位,不能超过30 for(int i=1;i<n;i++){int b;cin>>b;s[i+1]=s[i]^b;if(b==0)continue;h=0;while(b){h++;b/=2; }h-=1;//相同最高位1的前缀异或值相同 if(a[h]&&((s[i]>>h)&1)!=a1[h]) flag=0;if(!a[h])a2-=1;a[h]=1;a1[h]=(s[i]>>h)&1; }if(flag==0||(1<<a2)<k)cout<<-1<<endl;else {int a11=0;k-=1;int cnt=0;//确定a1 for(int i=0;i<30;i++){//根据最高位1的前缀异或,确定a1的对应位的值。 if(a[i])a11|=(a1[i]<<i);else{int m=((k>>cnt)&1)<<i;//未知位,根据k的二进制数分配 a11|=m;cnt++;}}for(int i=1;i<=n;i++){cout<<int(a11^s[i])<<" ";}cout<<endl; }}
}