首先要知道 (a&b)+(a|b)=a+b ①
我也不知道怎么才能想到这个,只能说按位运算是有很多规律的,以后遇到类似的题可以尝试着去寻找一些规律。
讲解:
已知 b[i]=∑(a[i]&a[j]),(1<=j<=n)
c[i]=∑(a[i]|a[j]),(1<=j<=n)
设d[i]=b[i]+c[i],
根据公式①,易得 d[i]=b[i]+c[i]=∑(a[i]&a[j])+∑(a[i]|a[j])=∑(a[i]&a[j]+a[i]|a[j])
=∑(a[i]+a[j])=n*a[i]+a[1]+a[2]+...+a[n],(1<=j<=n)
即 d[i]=n*a[i]+a[1]+a[2]+...+a[n] ②
所以 ∑d[i]= ∑(b[i]+c[i])=∑(n*a[i]+a[1]+a[2]+...+a[n])=2n*(a[1]+a[2]+...+a[n])
即 a[1]+a[2]+...+a[n]=∑d[i]/(2n) ③
讲③带入②,解得 a[i]=(d[i]-(∑d[i])/(2n))/n。
然后循环一遍就能求出唯一的a[i]。
但是要注意这个a[i]只是满足d[i],却不一定满足b[i]与c[i]。
所以要一定检查一遍,如果这个解同时也满足b[i]与c[i],那么就输出之,否则就无解。
至于检查的方式也是很有趣,如果带入原公式O(n^2)计算那就超时了。
方法是按位计算。因为计算公式很有特点,所以一个O(n)的循环就可以用一个O(1)的计算搞定,但付出的代价是必须一位一位的算。最终算法时间复杂度位O(nL),其中L是二进制位数。显然long long也就才64位啦。
a[i][j]表示第i个a的第j位,显然只能为0或者为1。b[i][j],c[i][j]同理。
bit[i]表示第i位是1的a的个数。
那么有b[i][k]=∑(a[i][k]&a[j][k]),(1<=j<=n,0<=k<L)
以及 c[i][k]=∑(a[i][k]|a[j][k]),(1<=j<=n,0<=k<L)
那么我们很容易就找到了这个O(1)计算的公式。
b[i][k]=a[i][k]?bit[k]:0
c[i][k]=a[i][k]?n:bit[k]
最后B[i]=∑(b[i][k]<<k)
以及C[i]=∑(c[i][k]<<k)
然后把B[i],C[i],与b[i],c[i]对比一下就知道答案是否符合了。
代码
#include<bits/stdc++.h>
#define maxn 200100
using namespace std;
typedef long long ll;
ll n;
ll a[maxn],b[maxn],c[maxn],d[maxn];
ll A[maxn][70],bit[70],B[maxn],C[maxn];
bool ok()
{
for(ll i=1;i<=n;i++)
if(a[i]<0)
return false;
for(ll i=1;i<=n;i++)
for(ll j=0;j<63;j++)
{
A[i][j]=a[i]&(1ll<<j)?1:0;
bit[j]+=A[i][j];
}
for(ll i=1;i<=n;i++)
for(ll j=0;j<63;j++)
{
ll bbit=A[i][j]?bit[j]:0;
ll cbit=A[i][j]?n:bit[j];
B[i]+=bbit<<j;
C[i]+=cbit<<j;
}
for(ll i=1;i<=n;i++)
if(B[i]!=b[i]||C[i]!=C[i])
return false;
return true;
}
void print()
{
for(ll i=1;i<=n;i++)
printf("%I64d%c",a[i],i==n?'\n':' ');
}
int main()
{
scanf("%I64d",&n);
for(ll i=1;i<=n;i++)
scanf("%I64d",&b[i]);
for(ll i=1;i<=n;i++)
{
scanf("%I64d",&c[i]);
d[i]=b[i]+c[i];
}
ll sum=0;
for(ll i=1;i<=n;i++)
sum+=d[i];
sum/=(2*n);
for(ll i=1;i<=n;i++)
a[i]=(d[i]-sum)/n;
if(ok()) print();
else puts("-1");
return 0;
}