Codeforces-1601A: Array Elimination
题目大意
题目传送门:codeforces-1601A
原题截图:
样例描述:
题目大意:
给定一个数组
{
a
i
}
\{a_i\}
{ai},每次可以选
k
k
k个元素进行消除,消除的方式是元素一起求AND,即
x
=
a
i
1
A
N
D
a
i
2
⋯
A
N
D
a
i
k
x = a_{i_1} \, AND \, a_{i_2} \, \cdots \, AND \, a_{i_k}
x=ai1ANDai2⋯ANDaik,之后,将这些元素减去
x
x
x,重复这一过程。目标是找出所有可能的
k
k
k, 使得数组最终被消为0。
题目解析
这道题应该考虑对于数组中每个数
a
j
a_j
aj ,将其展开成二进制,取第
i
i
i 个bit位得到的
a
j
(
i
)
a_j^{(i)}
aj(i) 。首先,在每一次消除中,如果
a
j
(
i
)
a_j^{(i)}
aj(i)被消除,那么这种变化一定是伴随着其它
k
−
1
k-1
k−1 个在
i
i
i bit位一起消除的。那么反过来看,既然对每个bit位的消除,每次必然有
k
k
k 个数的对应bit位会变成
0
0
0,那么如果最终得到的数列全是
0
0
0 的话,就意味着
k
k
k 一定是所有bit位标记为
1
1
1 的数组元素个数的公约数。现在我们证明了数组
数
组
能
够
消
为
全
0
⇒
k
是
所
有
b
i
t
位
为
1
的
数
字
个
数
的
公
约
数
数组能够消为全0 \Rightarrow k是所有bit位为1的数字个数的公约数
数组能够消为全0⇒k是所有bit位为1的数字个数的公约数,即我们证明了充分性。
那么还需要知道如果每次消除
k
k
k 个有公共bit为
1
1
1 的数组元素,是否能得到全
0
0
0 的数组。显然,每次选
k
k
k 个数的一个(或多个)公有bit位去消除,由于
k
k
k 整除
g
1
,
g
2
,
g
3
,
⋯
,
g
n
g_1,g_2,g_3,\cdots,g_n
g1,g2,g3,⋯,gn(
g
i
g_i
gi代表二进制第
i
i
i位为
1
1
1的数组元素的个数),显然
k
k
k 也整除
g
1
+
g
2
+
⋯
+
g
n
g_1+g_2+\cdots + g_n
g1+g2+⋯+gn,所以消除到最后,由于
k
k
k 本身也是每个bit位置为
1
1
1元素个数的公约数(这意味着如果有一个数组
{
b
i
}
\{b_i\}
{bi},代表第
i
i
i位非零的元素个数,每次在
{
b
i
}
\{b_i\}
{bi}的子集中的元素进行
−
k
-k
−k操作,最终一定能得到全
0
0
0),最终一定能得到全
0
0
0 的数组。
最后,综上可知,只要求出该组数中
g
1
,
g
2
,
⋯
,
g
n
g_1,g_2,\cdots,g_n
g1,g2,⋯,gn的最大公约数的约数,就是该题答案(最大公约数的约数就是该组数的所有公约数)。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 7;
int a[maxn], bits[32];
int gcd(int a, int b) { return b == 0? a: gcd(b, a % b);}
int main(){
int n, t;
cin >> t;
while(t--) {
cin >> n;
memset(bits, 0, sizeof(bits));
for(int i = 0; i < n; ++i) {
cin >> a[i];
for(int j = 0; j < 31; ++j)
bits[j] += (1 & (a[i] >> j));
}
int k = bits[0];
for(int j = 0; j <= 31; ++j) k = gcd(k, bits[j]);
if (k == 0) {
for (int i = 1; i <= n; ++i) cout << i << " ";
} else {
for (int i = 1; i <= k; ++i)
if (k % i == 0) cout << i << " ";
}
cout << endl;
}
return 0;
}