【zzulioj 1893 985的数学难题】

来源:互联网 发布:java long保留两位小数 编辑:程序博客网 时间:2024/04/30 05:51

985的数学难题

Description
985有n个正整数,他想快速知道下面函数的返回值
int a[N+1];
long long Solve() {
int i, j;
long long ans = 0;
for(i = 1; i <= N; i++) {
for(int j = i + 1; j <= N; j++) {
ans += a[i] + a[j] + (a[i] ^ a[j]) + (a[i] | a[j]) + (a[i] & a[j]);
}
}
return ans;
}
注:^表示异或运算。

Input
第一行输入一个整数t,代表有t组测试数据。
每组数据第一行输入一个整数代表元素个数,接下来一行输入n个正整数a[]。
注:1 <= t <= 30,1 <= n,a[] <= 100000。

Output
一个整数代表最后的返回值ans。

Sample Input
2
1
10
2
1 1
Sample Output
0
4

#include<stack>#include<cmath>#include<queue>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define   K   100011#define INF 0x3f3f3fusing namespace std;bool cmp(int a,int b){    return a>b;}long long pa[K];int main(){   int i,j;   int N;   int T;   long long ans;   long long ml;   long long cot;   scanf("%d",&T);   while(T--)   {    scanf("%d",&N);    ans=0;    for(i=1;i<=N;i++)    {        scanf("%lld",&pa[i]);        ans+=pa[i];    }    ans*=(N-1);  //先把和求出,每个数相加时都用到了(N-1)次 ;    sort(pa+1,pa+N+1,cmp);     ml=1;     //做为每次尾数更新时的见证    while(pa[1]) //当最大的数小于 1 时跳出循环     {        cot=0;    //初始化尾数为 1 的个数         for(i=1;i<=N;i++)        {            if(pa[i]==0)  //若a[i]为零,则剩下的数定全为零             break;            if(pa[i]&1)  //每次只判断尾数是否为为 1            cot++;            pa[i]>>=1; //更新尾数         }        ans+=(cot*(cot-1)>>1)*ml; //只有当两个数的尾数同时才有贡献,从尾数为1的数里挑出两个,总数为(cot*(n-cot)/2);         ans+=(cot*(N-cot)+(cot*(cot-1)>>1))*ml; //当一个数的尾数为 1 时就有贡献,先从尾数为1和0的数里各挑出一个,然后从尾数为 1 的数里挑出两个         ans+=(cot*(N-cot))*ml;  // 只有当尾数不同时才有贡献,从尾数为1和0的个数里各挑出一个,总数为(cot*(n-cot));         ml<<=1;  //更新每次 ml 的值,尾数每更新一次,ml左移一位;    }    printf("%lld\n",ans);   }   return 0;}
0 0