zzulioj1893: 985的數學難題(二進位制計算)

Zhac發表於2016-08-09
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

很顯然不能直接寫函式計算
這種型別的題目涉及到二進位制運算
有定理x^y+x&y==x|y
考慮二進位制的每一位對結果的影響
比如1101、1001、1010進行上述運算
則可發現:
從右到左每一位上有1的個數記為
cnt[0]~cnt[3]分別為2、1、1、3
因為或運算除了0|0==0
其餘都為1也就是0|1+1|1.
依次看二進位制末尾有多少數貢獻了1,再根據位運算的性質進行計數即可。

程式碼:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
bool cmp(int x,int y)
{
	return x>y;
}
int main()
{
	int t,i;
	int a[100010];
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		long long sum=0;
		for(i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			sum+=a[i];
		}
		sum=(n-1)*sum;
		sort(a+1,a+n+1,cmp);
		long long m=1,ans;
		while(a[1])
		{
			ans=0;
			for(int i=1;i<=n;i++)
			{
				if(!a[i])
				break;
				if(a[i]&1)
				ans++;
				a[i]>>=1;
			}
			sum+=(ans*(n-ans)+((ans-1)*ans/2))*m*2;
			m<<=1;
		}
		printf("%lld\n",sum);
	}
	return 0;
}


相關文章