1893: 985的数学难题
Time Limit: 2 Sec Memory Limit: 128 MBSubmit: 138 Solved: 27
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
HINT
Source
深入了解位运算的题!!原理勉强懂了,最后还是看别人代码搞定的……
这一题把数字转换成二进制来计算,然后再转回去。具体解释写注释里。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
long long n,ans;
long long num[1000000+19];
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
int i,T;
scanf("%d",&T);
while(T--)
{
scanf("%lld",&n);
ans=0;
for(i=1;i<=n;i++)
{
scanf("%d",&num[i]);
ans+=num[i];
}
ans*=(n-1);//前面的相加
sort(num+1,num+n+1,cmp);//把最大的数字放前面,这样所有位数都不会落掉
long long mul=1,ant;
while(num[1])
{
ant=0;
for(i=1;i<=n;i++)//记录每一个数字每一位的1的个数
{
if(num[i]==0)
break;
if(num[i]&1)
ant++;
num[i]>>=1;//去掉已经被记录的这一位
}
ans+=(((ant-1)*ant)>>1)*mul;//与运算,所有的这位数为1的数相结合
ans+=((n-ant)*ant+(((ant-1)*ant)>>1))*mul;//或运算,只要有1就算
ans+=((n-ant)*ant)*mul;//异或运算,这一位为0的和这一位为1的相结合
mul<<=1;//这一位真实的数字,比如说最末尾那一位mul=1(2º),倒数第二的那位mul=2(2¹)
}
printf("%lld\n",ans);
}
return 0;
}