1893: 985的数学难题
Time Limit: 2 Sec Memory Limit: 128 MBSubmit: 120 Solved: 21
Submit Status Web Board
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
首先分析所给源代码,其意是让求所给整数两两之和,两两与运算,或运算,异或运算,然后求总和;
对于两两之和,可以用公式,ans=sum*(n-1);
但进行位运算时,则需要将其化为二进制考虑;
奇数二进制最后一位为1,而偶数二进制最后一位为0;
与运算,同一为一,不同为零
或运算,有一为一,无一为零
异或运算,不同为一,相同为零
代码分析
<pre name="code" class="cpp">#include <cstdio> #include <cstring> #include <algorithm> using namespace std; long long num[1000000]; long long ans; bool cmp(int a,int b) { return a > b; } int main() { long long n; int u; scanf ("%d",&u); while (u--) {memset(a,b,sizeof(a)); scanf("%lld",&n); ans = 0; for (int i = 1 ; i <= n ; i++) { scanf ("%d",&num[i]); ans += num[i]; } ans *= (n-1);//两两之和最后之和 sort(num+1,num+1+n,cmp);//所有数字排序 long long mul = 1;//表示所在位数,结果想加时,保证数的大小不变 long long ant;//二进制末尾为1的个数 while (num[1]) { ant = 0; for (int i = 1 ; i <= n ; i++) { if (num[i] == 0) break; if (num[i] & 1) ant++;//判断其二进制最后一位是否为一 num[i] >>= 1;//将其二进制数右移一位 } ans+=(((ant-1) * ant) >> 1) * mul; //共有ant个一,对其排列组合 //与运算 ans+=((n-ant) * ant + (((ant-1) * ant) >> 1)) * mul;//只要有一结果都为一,有一和没一排列组合,有一排列组合 //或运算 ans+=((n-ant) * ant) * mul; //异或运算 mul <<= 1; } printf ("%lld\n",ans); }}