2023牛客暑期多校训练营7-c-Beautiful Sequence

 思路:

a_{i}\bigotimes a_{i+1}=b_{i}\rightarrow a_{i}\bigotimes a_{i+1}\bigotimes a_{i+1}=b_{i}\bigotimes a_{i+1}\rightarrow a_{i}= b_{i}\bigotimes a_{i+1},则有a_{i}=a_{1}\bigotimes b_{1}\bigotimes b_{2}...\bigotimes b_{i-1},也就是说只要知道A1就可以求任意A。由于A是升序排列,所以对于任意B_{i},二进制所包含1的最高位第k位来说,表明A_{i}A_{i+1}第k位相反,A_{i+1}要大一些,所以它的第k位为1,A_{i}的第k位为0,例如Bi=10对应的二进制数为1010,最高位1就是第3位,所以就能确定Ai+1的第三位为1,Ai的第三位为0;类似这样操作,就能找出A中很多确定的值,不确定的位根据k去判断。为了方便计算,我们的是要去预处理b的前缀异或s[i]=b_{1}\bigotimes b_{2}...\bigotimes b_{i-1},然后解出a1就能得出,为了找到a1的某些确定值,我们同样的去找bi最高位1为第k位,然后记录s[i]的第k位的值,因为要使a[i+1]的第k位为1,由于a_{i+1}=a_{1}\bigotimes s_{i}\bigotimes b_{i},那么只要记录下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; 
		}
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值