P6102 谔运算 解题报告(数论?)

题目

链接:https://www.luogu.com.cn/problem/P6102

思路分析

这道题。。。写了好久,看了大佬博客写出来的(太菜了。。。)。
大佬题解:https://www.luogu.com.cn/blog/Feliks-YB/post-ti-xie-p6102-post
这道题是这样做的:每读入一个数,就把这个数转化为32位的二进制数。需要明白一点:or、ans、xor这些运算都只和一个二进制位上的有关系。然后统计下这32位上每一位出现1的次数和出现0的次数(下面需要用到类似概率统计的方法,所以这里统计频数)。根据统计:对于1、0这两个数分为(ai,aj,ak,al)的排列中:

(1,1,0,0),(1,0,1,0),(1,0,0,1),(0,1,0,1)(0,0,1,1)(1,1,1,0)(1,1,0,1)(1,0,0,0)(0,1,0,0)(0,1,1,0)

这10种排列计算的结果为1。那么,对于输入的这n个数,我们去它最右边的二进制位的统计结果,记1的频数为p1,0的频数为p0,则:这一位上得到1的频数为p1p1p0p06(6为在上面包含2个1和2个0的组合的个数为6)+p1p0p0p02(2和上面的6是一个道理)+p0*p1p1p12(同理),这是一位上1的频数。
我们再来看看相加的时候:按照二进制加法,相加的时候其实就是二进制上对应位置上的数相加,满1就向前进一位,那么,我们相加的时候也可以用相同的手法:我们统计出了每一位上1的频数,那么我们每一位分别处理:
假设第一位上1的频数为a1,下面一次类推,则:第一位上结果为a1*1,第二位上是a2
1……那么,我们组成的这个数就是:
a32a31……a2a1(但是每一位上还需要进位)
例如a1=5,a2=3,其他都是0,那么,这个数就是
000……32
然后,再满2进1一下,这个是就是00000……1000,转为10进制就是2^3=8,这个就是我们的答案。那么,这个相加的过程,我们就可以用位运算符<<帮我们实现。

完整代码

#include <iostream>
using namespace std;
const long long mod = 4294967296;
typedef long long ll;
unsigned int a[500005] = { 0 };
int cnt[32][2]={0}; 

int main()
{
	ios::sync_with_stdio(false);
	ll n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a[i];
		for(int j=0;j<32;j++)
		{
			if(a[i]&(1<<j)) cnt[j][1]++;
			else cnt[j][0]++;
		}
	}
	unsigned ans=0;
	for(int i=0;i<32;i++)
	{
		unsigned int res=(cnt[i][1]*cnt[i][1]*cnt[i][0]*cnt[i][0])*6;
		res+=(cnt[i][1]*cnt[i][0]*cnt[i][0]*cnt[i][0])<<1;
		res+=(cnt[i][0]*cnt[i][1]*cnt[i][1]*cnt[i][1])<<1;
		ans+=res<<i;
	}
	cout << ans << endl;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值