http://www.bnuoj.com/bnuoj/problem_show.php?pid=1065
1 2 18467 6334
70239
思路:这道题目,必须感谢队友刘庆的想法......
比如现在有n(n==3)个数,分别是:2 5 7
将它们转化为二进制: 0010 0101 0111
那么,现在只看二进制,我们将这三个二进制加起来,但不进位,只统计二进制各个位上面的1的个数会得到:
1 1 1 1
0 2 2 2
这表示,二进制第三位没有1,第二位有2个1,第一位有2个1,第0位有2个1,这些位对应:2^3 2^2 2^1 2^0
那么会发现当2|2+2|5+2|7==2*2^0+n*2^1+2*2^2+0*2^3
5|2+5|5+5|7==n*2^0+2*2^1+n*2^2+0*2^3
7|2+7|5+7|7==n*2^0+n*2^1+n*2^2+0*2^3
发现没有,当一个数,比如7的二进制0111去或其他数的时候,若有一位本身是1,那么这一位或上与之对应的那一位(不管是0还是1)形成的新的数字的这一位都会是1;
就比如000110 与010000 或 变成010110 ,会发现只要有1的位,所形成新的二进制那一位也必然有1,那么当它与n个二进制数字或操作,所形成新的二进制数字,当原数字有1那么它对应的那一位也必然是1的.....这样,我们就只需要统计所以的二进制加起来不产生进位的情况下,每一位有多少个1就好 。
代码:
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; struct node { int a[20]; int cnt; int num; }s[10005]; int t[20],f=0; int p[20]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072}; int main() { int text; scanf("%d",&text); while(text--) { memset(s,0,sizeof(s)); memset(t,0,sizeof(t)); int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&s[i].num); int tmp=s[i].num; while(tmp>0) { int tmp1=s[i].cnt; s[i].a[tmp1]=tmp%2; tmp/=2; s[i].cnt++; } for(int j=0;j<=15;j++) if(s[i].a[j]==1) t[j]++; //for(int i=0;i<=15;i++) //printf("%d",t[i]); } int ans=0; for(int i=1;i<=n;i++) { for(int j=0;j<=15;j++) { if(s[i].a[j]==1) { ans+=p[j]*n; } if(s[i].a[j]==0) { ans+=t[j]*p[j]; } } } printf("%d\n",ans); } return 0; }