CF1602.C. Array Elimination(逻辑运算&)

C. Array Elimination(逻辑运算&)

题意:

给出一组数,对于一个数k,每次可以选择k个位置进行若干次操作:k个位置上的数减去这k个数的与值
求出所有能够使得这组数都变为 0 的数 k。

思路:

要把所有数都变为0,也就是将所有数的数位变为0。
每次操作,减去的是k个数的与值。所以,为了将一个数位由1变为0,减去的这个与值的该数位要为1。
为了让与值的该数位为1,那么挑选的k个位置上的数该数位都为1。

因为可以操作若干次,所以对于一列数位的 x 个1来说,可以选择 x 的因子 y,能够将y个数的该数位都化为0,然后进行若干次,就可以将 x 个数的该数位都变为 0。

综合考虑所有数位,那么满足条件的 k 就为30个数位中,当前位为 1 的数的个数的公约数

一个数的某数位为1,减去一个该数位同样为1的数,这个数位就变成0了。

求一组数的公约数 = 求其gcd的所有因子。

对于这样位运算的题,不要看整个数,要看每个数位之间的操作和变化。

Code:

const int N = 200010, mod = 1e9+7;
int T, n, m, a[N], ans[N];
int f[35];

void pd(int x)
{
	for(int i=0;i<=30;i++)
	{
		if(x&(1<<i)) f[i]++;
	}
}

void prim(int x)
{
	int cnt=0;
	for(int i=1;i<=x/i;i++)
	{
		if(x%i==0){
			ans[++cnt]=i;
			if(x/i!=i) ans[++cnt]=x/i;
		}
	}
	sort(ans+1,ans+cnt+1);
	
	for(int i=1;i<=cnt;i++) cout<<ans[i]<<" ";
	cout<<endl;
} 

int main(){
	Ios;
	
	cin>>T;
	while(T--)
	{
		cin>>n;
		
		mem(f,0);
		for(int i=1;i<=n;i++){
			int x;cin>>x;
			pd(x);
		}
		
		int g;
		for(int i=0;i<=30;i++){
			if(i==0) g=f[i];
			else g=__gcd(g,f[i]);
		}
		
		if(!g) for(int i=1;i<=n;i++) cout<<i<<" ";
		prim(g);
	}
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值