题目:
你有a1到an个数,现在让你选K个数,X=a1&a2&......&ak,让这k个数再减去X,求能使得a1~an都为0的k值可能为什么?
题解:
我们可以将数字转成二进制来解决,拿案例来说明:
13:0 1 1 0 1
7:0 0 1 1 1
25:1 1 0 0 1
19:1 0 0 1 1
当k=1时,自己减去自己。
当k=2时:会使得都为1的地方为0。
13和7配对 :01000和00010
25和19配对:01000和00010
接下来结果就很显然了,直接相同的配对,成功。
当k=3时:当全部为1时,&才能为1
最后一行会因为 有一个1剩下 和 其他的1都无法消除 而无法配对成功。
当k=4时,会因为前几列的1无法消除而配对失败。
因此我们只需要取得每一列的gcd(),取得它们的最大因数;而后的答案就为这个最大因数的因数。(注:若最大因数为0,则表示数全为0,答案为1~n)
#include<bits/stdc++.h>
#define ms(a) memset(a,0,sizeof(a));
typedef long long ll;
using namespace std;
const int N = 2e5 + 5;
int ans[N], b[35];
void cb(int a) {
for (int i = 0; i < 30; i++) {
if (a & 1)b[i]++;
a >>= 1;
if (a == 0)break;
}
}
int gcd(int a, int b) {
return b > 0 ? gcd(b, a % b) : a;
}
void prim(int x) {
int cnt = 0;
for (int i = 1; i <= sqrt(x); i++) {
if (x % i == 0) {
ans[cnt++] = i;
if (i*i!=x)ans[cnt++] = x / i;
}
}
sort(ans, ans + cnt);
for (int i = 0; i < cnt; i++)
cout << ans[i] << " ";
}
void solve(){
ms(b);
int n,a;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a;
cb(a);
}
int g = b[0];
for (int i = 1; i < 30; i++) {
g =gcd(g,b[i]);
}
if (g) prim(g);
else for (int i = 1; i <= n; i++)
cout << i << " ";
cout << endl;
}
int main() {
int t;
cin >> t;
while (t--) {
solve();
}
}