c题题解:

alt alt

#include<bits/stdc++.h>

using namespace std;

const int N = 1e6+100;

int a[N],b[N],f[N];//f[i]表示从b1到bi的异或和,特殊地,我们规定f[0]=0;
int num[30];//记录a1二进制表示上的各个位数
bool flag;//有没有出现矛盾的标记

int n,k,t;

signed main()
{
    cin>>t;
    while(t--)
    {
        flag=false;//初始化
        cin>>n>>k;
        f[0]=0;
        a[1]=0;
        for(int i=0;i<=29;i++)num[i]=-1;
        for(int i=1;i<=n-1;i++)
        {
            cin>>b[i];
            f[i]=f[i-1]^b[i];//求异或和
        }
        for(int i=0;i<n-1;i++)
        {
            if(flag)break;
            for(int j=29;j>=0;j--)
            {
                if((f[i]>>j&1)!=(f[i+1]>>j&1))//找到了不同位,进行比较
                {
                    if(num[j]==-1)
                    {
                        num[j]=(f[i]>>j&1);
                    }
                    else if(num[j]!=(f[i]>>j&1))
                    {
                        flag=true;//出现了矛盾,标记起来
                    }
                    break;//一但找到不同位,比较完之后直接退出
                }
            }
        }
        if(flag)
        {
            cout<<-1<<endl;
            continue;
        }
        k--;
        int s=0;//方案总数-1
        for(int i=29;i>=0;i--)if(num[i]==-1)s=s*2+1;
        if(s<k)//判断存不存在字典序第k小的方案
        {
            cout<<-1<<endl;
            continue;
        }
        int p=0;
        while(k)//将k拆成二进制,填充到a1的二进制表示中,已经确定的值保持不变
        {
            int x=k&1;
            while(num[p]!=-1)p++;
            num[p]=x;
            k = k >> 1;
        }
        for(int i=0;i<=29;i++)if(num[i]==-1)num[i]=0;//将剩下未填充的数位初始化为0
        for(int i=29;i>=0;i--)a[1]=a[1]*2+num[i];//计算a1,注意从最后一位开始算
        for(int i=2;i<=n;i++)a[i]=a[i-1]^b[i-1];//计算剩下的值
        if(a[n]>=pow(2,30))//判断序列A中是否存在大于等于2^30的数
        {
            cout<<-1<<endl;
            continue;
        }
        for(int i=1;i<=n;i++)cout<<a[i]<<" ";
        cout<<endl;
    }
}