Codeforces Round #750 (Div. 2) C. Array Elimination
思路
- 数组中的元素最多有30位,对数组中的所有元素,统计0~29位上1出现的个数。设第0位为最右边一位。
-
例如,对
13 7 25 19
,写成二进制为1101、0111、11001、10011,则第0位到第5位1的个数分别为4、2、2、2、2,第6位到第29位的1的个数为0
-
对这30位上的1的个数取最大公约数。
int res = 0;
for (int i = 0; i < 30; i++)
{
res = gcd(res, bits[i]);
}
-
答案为res的所有因子。
注意:res的因子包含1和res本身,而且也包含合数,不是只取质因子
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 200010;
LL a[N];
int bits[31]; // 记录第i位上1的个数
int ans[N], cnt; // 答案数组,每个test case要初始化
int gcd(int a, int b)
{
if (b == 0)
{
return a;
}
return gcd(b, a % b);
}
// 求x的所有因子,包含1和res本身,并且包含为合数的因子
void divide(int x)
{
for (int i = 1; i <= x / 2; i++)
{
if (x % i == 0)
{
ans[cnt++] = i;
}
}
ans[cnt++] = x;
}
void init()
{
memset(bits, 0, sizeof bits);
memset(ans, 0, sizeof ans);
cnt = 0;
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
{
init();
int n;
cin >> n;
// 每输入一个元素a[i],就判断它每个位上是否为1
// 是的话,这一位上1的个数就+1
for (int i = 0; i < n; i++)
{
cin >> a[i];
for (int j = 0; a[i]; j++)
{
if (a[i] & 1)
{
bits[j]++;
}
a[i] >>= 1;
}
}
// 求30个位上的1的个数的最大公因子res
int res = 0;
for (int i = 0; i < 30; i++)
{
res = gcd(res, bits[i]);
}
// 如果res==0,说明原数组每一个元素都为0,则ans数组为1~n
if (res == 0)
{
for (int i = 1; i <= n; i++)
{
ans[cnt++] = i;
}
}
else
{
divide(res);
}
for (int i = 0; i < cnt; i++)
{
cout << ans[i] << ' ';
}
cout << endl;
}
return 0;
}