【zzulioj 1893 985的数学难题】

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
#include
#include
#include
#include
#include
#include
#define   K   100011
#define INF 0x3f3f3f
using 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;
}

你可能感兴趣的:(zzulioj,小数学,训练赛)