Codeforces Round #379 (Div. 2) F. Anton and School
题意:
给你n对 b[i], c[i], 让你求a[i],不存在输出-1
b[i] = (a[i] and a[1]) + (a[i] and a[2]) + (a[i] and a[3]) +...+ (a[i] and a[n]);
c[i] = (a[i] or a[1]) + (a[i] or a[2]) + (a[i] or a[3]) +...+ (a[i] or a[n]);
and 和 or 是按位与 或
思路:
(a and b) + (a or b) = (a + b) 证明显然
所以把每个b[i]+c[i] = n*a[i] + s, s为所有a的和
这样 就可以解出每个 a[i]了,且解唯一,证明比较显然
但是,解出的解不一定就是正确解!
为什么会这样呢?
因为解方程的时候 把b[i] c[i]看成了一个整体。
也就是他们的和是满足的,但是他们自身可能不满足。
举个例子:n = 1, b[0] = 3, c[0] = 5;
发现用上面的方法是有解的 a[0] = 4, 但是很显然,这个也并不合法
所有我们需要检测每一个b,c是否合法。
n那么大,暴力n方肯定是不行了。
我们要这样操作:
用A[i][j]表示 a[i]的第j位是否为1,顺便求出k[j],k[j]表示所有a中的第j位有多少个1 处理的时间复杂度O(n*logv)
再求出B[i][j], C[i][j]
B[i][j] = (A[1][j] and A[i][j]) + (A[2][j] and A[i][j]) + ... + (A[n][j] and A[i][j]);
C[i][j] = (A[1][j] or A[i][j]) + (A[2][j] or A[i][j]) + ... + (A[n][j] or A[i][j]);
这个不用暴力求,因为我们刚刚已经求出了k[j]
显然地,有下面的式子:
if A[i][j] = 0: B[i][j] = 0, C[i][j] = k[j]
else B[i][j] = k[j], C[i][j] = n
有了B C后我们就能很快的求出b, c了
b[i] = B[i][0]*2^0 + B[i][1]*2^1 + ...
c[i] = C[i][0]*2^0 + C[i][1]*2^1 + ...
最终的时间复杂度O(n*logv), v=max(a1,a2,..,an)
具体代码如下:
1 const int maxn = 200000 + 10; 2 LL b[maxn], c[maxn], a[maxn]; 3 LL A[maxn][35], B[maxn][35], C[maxn][35], k[maxn]; 4 LL s; 5 int n; 6 7 void init() 8 { 9 scanf("%d", &n); 10 for (int i = 0; i < n; i ++) scanf("%lld", b + i); 11 for (int i = 0; i < n; i ++) scanf("%lld", c + i); 12 } 13 14 bool check() //返回求出的答案是否合法 15 { 16 for (int j = 0; j < 31; j++) 17 { 18 for (int i = 0; i < n; i++) 19 { 20 A[i][j] = a[i] & (1ll << j) ? 1 : 0; 21 k[j] += A[i][j]; 22 } 23 } 24 for (int j = 0; j < 31; j++) 25 { 26 for (int i = 0; i < n; i++) 27 { 28 if (A[i][j]) 29 { 30 B[i][j] = k[j]; 31 C[i][j] = n; 32 } 33 else 34 { 35 B[i][j] = 0; 36 C[i][j] = k[j]; 37 } 38 } 39 } 40 41 for (int i = 0; i < n; i++) 42 { 43 LL sumB = 0, sumC = 0; 44 for (int j = 0; j < 31; j++) 45 { 46 sumB += B[i][j] * (1ll << j); 47 sumC += C[i][j] * (1ll << j); 48 } 49 if (sumB != b[i] || sumC != c[i]) return false; 50 } 51 return true; 52 } 53 54 void solve() 55 { 56 bool ans = true; 57 for (int i = 0; i < n; i++) 58 { 59 s += b[i] + c[i]; 60 } 61 if (s % (2 * n)) ans = false; 62 s /= 2 * n; 63 for (int i = 0; i < n; i++) 64 { 65 a[i] = (b[i] + c[i] - s) / n; 66 if ((b[i] + c[i] - s) % n) ans = false; 67 } 68 if (!ans || !check()) printf("-1\n"); 69 else 70 { 71 for (int i = 0; i < n;i ++) 72 { 73 printf("%lld ", a[i]); 74 } 75 } 76 } 77 78 int main() 79 { 80 init(); 81 solve(); 82 return 0; 83 }