1893: 985的数学难题
Time Limit: 2 Sec Memory Limit: 128 MB
Submit: 140 Solved: 28
SubmitStatusWeb BoardDescription
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
HINT
Source
hpu
SubmitStatusWeb Board
对于加法可以每个数相加乘n-1就好了至于其他的计算出每一位做的贡献最后相加 详细的直接看代码好了
#include<cstdio>
#include<algorithm>
using namespace std;
bool cmp(int a,int b){
return a>b;
}
long long a[100010];
int main(){
int T;
scanf("%d",&T);
while(T--){
int n; int i=0;
scanf("%d",&n);
long long sum=0;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
sum+=a[i];
}
sum*=(n-1); //每个数加了n-1次
long long ml=1;
long long ans=0;
sort(a+1,a+1+n,cmp);
while( a[1] ){
ans = 0;
for( i=1 ; i<=n ; i++)
{
if(a[i]==0)
break;
if(a[i]&1)
ans++; //计算出末尾有多少在某一位 末尾有多少的 1
a[i] >>= 1;
}
sum += ( ans * (ans-1) >> 1 ) * ml;
// 计算与运算 从 ans 个 1 中选出两个因为全是 1 才加1 可贡献C( 2,ans );
sum += ( ( ans * ( n-ans ) ) + ( ans * ( ans-1 ) >> 1 ) ) * ml;
// 或运算对这一位的贡献有0 n-ans 个有 1 ans个 从中选出一个零或1 可以贡献一个1 可贡献ans*(n-ans)
// 有ans 个1 从中选出来两也可以贡献一个1 可贡献C( 2,ans )
// 两种情况相加即可;
sum += ( ans * ( n - ans ) ) * ml;
// 异或中只有0 和 1 才可以贡献一个 1 贡献 ans*(n-ans)个1 ;
ml <<= 1;//注意每一位都要乘 2的位数平方
}
printf("%lld\n",sum);
}
return 0;
}