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 }

 

posted @ 2016-11-18 09:41  llysrv  阅读(94)  评论(0编辑  收藏  举报