题目:http://codeforces.com/problemset/problem/734/F
Anton goes to school, his favorite lessons are arraystudying. He usually solves all the tasks pretty fast, but this time the teacher gave him a complicated one: given two arrays b and c of length n, find array a, such that:
where a and b means bitwise AND, while a or b means bitwise OR.
Usually Anton is good in arraystudying, but this problem is too hard, so Anton asks you to help.
The first line of the input contains a single integers n (1 ≤ n ≤ 200 000) — the size of arrays b and c.
The second line contains n integers bi (0 ≤ bi ≤ 109) — elements of the array b.
Third line contains n integers ci (0 ≤ ci ≤ 109) — elements of the array c.
If there is no solution, print - 1.
Otherwise, the only line of the output should contain n non-negative integers ai — elements of the array a. If there are multiple possible solutions, you may print any of them.
4
6 8 4 4
16 22 10 10
3 5 1 1
5
8 25 14 7 16
19 6 9 4 25
-1
解析
这是一道乱搞思路题。
感谢jhy大佬的推荐顺便宣传一下他的博客http://www.cnblogs.com/JYYHH/
好了步入正题:
考虑两个数b,c,把他们拆成二进制一位一位看。
a&b 在第k为为1的条件是a和b的第k位都为1
a|b 则是在第k为有一个为1即可。
为什么我们要分析这个呢?
因为也没有什么可以乱搞的了
我们来计算一下(a&b)+(a|b),
如果两个数(二进制)第k位都为1,那么
第k位的贡献就是2*(1<<k),(包含第0位)。
如果只有一个数为1,那么
贡献就是(1<<k),
否则贡献为0,
这样子得到的结果,是不是和a+b的结果一样?
好了经过乱搞我们得到了一个等式(a&b)+(a|b)==a+b
这个等式回头再用。
好了我们得到了这个等式是来乱搞转化的。
我们尝试去求a。
我们知道了:
b[i]=sigma(ai&aj) c[i]=sigma(ai|aj),
令f[i]=b[i]+c[i] ==> f[i]=n*a[i]+sigma(aj)。
我们把sigma(ai)消去:
sigma(f[i])=2n*sigma(aj) sigma(aj)=sigma(f[i])/2n
然后我们带入原来推出来的:
得到:a[i]=(f[i]-sigma(f[i]/2n))/n。
注意:此时得到的ai不一定能满足原来的bi,ci的条件,
所以我们要用n^2的方法去检查一下是否满足条件
正常方法检查超时稳稳的。
我们还是只能——乱搞用位运算来转化。
由于我们已经知道了ai,可以尝试用ai去推出bi和ci的值。
先考虑b:
考虑bi的每一位,假设考虑第k位,
如果ai的第k位为1,那么对bi这个数的贡献就是:
在a中第k为为1的ai个数<<j。
好吧我们定义一下变量:
a[i][k]代表ai的第k位是什么数,g[x]代表第x位为1的ai的个数,
我们设cb[i][k]代表求出来的bi的第k位对bi总体的贡献。
那么我们易知:
b[i]=sigma(cb[i][k]<<k),
那么cb[i][k]和ai有关,我们可以找到关系:
cb[i][k]=0 a[i][k]==0
g[k] a[i][k]==1
好了对此我们就可以快速算出bi的值,跟原来的bi比较了。
ci的算法也同理,c[i][k]的算法请自行思考其实你们可以直接看代码的orz。
好了蒟蒻的代码献上:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 #define ll long long 8 const int maxn=200010; 9 int n; 10 ll sum; 11 ll a[maxn],b[maxn],c[maxn]; 12 ll f[maxn],g[maxn]; 13 ll ca[maxn][35],cb[maxn],cc[maxn]; 14 bool check(){ 15 for (int i=1;i<=n;++i){ 16 for (int j=0;j<=31;++j){ 17 ca[i][j]=a[i]&(1<<j)?1:0; 18 g[j]+=ca[i][j]; 19 } 20 } 21 for (int i=1;i<=n;++i){ 22 for (int j=0;j<=31;++j){ 23 ll ckb=ca[i][j]?g[j]:0; 24 ll ckc=ca[i][j]?n:g[j]; 25 cb[i]+=ckb<<j; cc[i]+=ckc<<j; 26 } 27 } 28 for (int i=1;i<=n;++i){ 29 if (cb[i]!=b[i]||cc[i]!=c[i]) return false; 30 } 31 return true; 32 } 33 int main(){ 34 scanf("%d",&n); 35 for (int i=1;i<=n;++i){ 36 scanf("%lld",&b[i]); 37 } 38 for (int i=1;i<=n;++i){ 39 scanf("%lld",&c[i]); 40 } 41 for (int i=1;i<=n;++i){ 42 f[i]=b[i]+c[i]; 43 sum+=f[i]; 44 } 45 sum/=2*n; 46 for (int i=1;i<=n;++i){ 47 a[i]=(f[i]-sum)/n; 48 } 49 if (check()){ 50 for (int i=1;i<=n;++i) 51 printf("%lld ",a[i]); 52 }else{ 53 printf("-1"); 54 } 55 return 0; 56 }