其他分享
首页 > 其他分享> > [CodeChef(July)221 Div.4 G]Find A, B, C

[CodeChef(July)221 Div.4 G]Find A, B, C

作者:互联网

做题时间:2022.7.11

\(【题目描述】\)

有三个非负整数 \(A,B,C\) 与一个正整数 \(N(N\leq 2\times 10^5)\) 满足 \(A,B,C\leq N\) ,给定 \(N+1\) 个函数 \(f(0),f(1),...,f(N)\) ,对于 \(\forall i,0\leq i\leq N\) 满足 \(f(i)=(A \oplus i )+(B\oplus i)+(C\oplus i)\) ,求出任意一组满足条件的 \(A,B,C\) (题目保证有解)

\(【输入格式】\)

第一行一个整数 \(T\) 表示数据组数
每组数据第一行一个整数 \(N\)
第二行 \(N+1\) 个整数表示 \(f\)

\(【输出格式】\)

共 \(T\) 行,每行三个整数表示 \(A,B,C\)

\(【考点】\)

位运算

\(【做法】\)

对于两个不同的 \(f(i)\) 和 \(f(j)\) 来说如果 \(i\) 与 \(j\) 在二进制表示下仅有一位相同,那么就可以推出那一位上 \(A,B,C\) 的情况

具体而言,若 \(i\) 与 \(j\) 的第 \(k\) 位不相同(假设 \(i_k=1,j_k=0\) ),那么 \(f(j)-f(i)=(A\oplus i)-(A\oplus j)+(B\oplus i)-(B\oplus j)+(C\oplus i)-(C\oplus j)=2^k\times (A_k+B_k+C_k)\)

即:

\[A_k+B_k+C_k=\frac{f(j)-f(i)}{2^k} \]

也就是说我们能够知道三个数的第 \(k\) 位的和。 注意:在确定了三者的和后, \(A_k\) , \(B_k\) 与 \(C_k\) 是无所谓谁是1谁是0的 ,因为在运算过程中 \(A,B,C\) 总是一起参与,且位运算不影响进位。

对于 \(A_k,B_k,C_k\) 的第 \(k\) 位而言,如果其中一个是1,那么异或后对 \(A_k+B_k+C_k\) 的贡献为 \(-1\) ,若它是 \(0\) ,那么异或后对 \(A_k+B_k+C_k\) 的贡献为 \(1\) ,所以最后 \(A_k+B_k+C_k\) 的值为 \([-3,-1,1,3]\) ,对应1的个数为 \([3,2,1,0]\)

只要知道所有的 \(0\leq 2^k\leq N\) 的 \(k\) 即可,可以通过 \(f(2^k)\) 与 \(f(0)\) 进行上述计算,得出第 \(k\) 位的结果。

需要注意的是,给 \(A_k,B_k,C_k\) 赋值的时候其中一个可能超过 \(N\) ,因此可以考虑倒序处理,并且每次率先给最小的赋值。

\(【代码】\)

#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cmath>
using namespace std;
const int N=1e5+50;
int f[N],n,T;
int main()
{
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		int a[3]={0,0,0};
		for(int i=0;i<=n;i++) scanf("%d",&f[i]);
		
		
		for(int k=18;k>=0;k--){//倒序处理 
			int i=(1<<k);
			if(i>n) continue;
			int tt;
			sort(a,a+3);//将a,b,c中最小的率先赋值,平均三者大小 
			
			//计算(f(i)-f(0))/2^k的值 
			if(f[i]>f[0]){//大于0 
				tt=(f[i]-f[0])/i;
				if(tt==1) a[0]^=i;
			}
			else{//小于0 
				tt=(f[0]-f[i])/i;
				if(tt==3) a[0]^=i,a[1]^=i,a[2]^=i;
				if(tt==1) a[0]^=i,a[1]^=i;
			}
		}
		printf("%d %d %d\n",a[0],a[1],a[2]);
	}
	return 0;
}

标签:int,tt,整数,Find,leq,oplus,include,July,Div.4
来源: https://www.cnblogs.com/Unlimited-Chan/p/16467851.html