【zzulioj 1893 985的数学难题】

30 篇文章 0 订阅
11 篇文章 0 订阅

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 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值