1893: 985的数学难题
Time Limit: 2 Sec Memory Limit: 128 MBSubmit: 161 Solved: 37
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
郁闷,各种对拍,随机数,自己写数据,都和暴力的没有区别,就是WA,结果数组改为long long 就过了……
思路:用sum[i][j]表示到第i个数有多少个数二进制的j位置上为零。a|b = a^b + a&b,所以只要统计a|b就可以了。对于 A i | A (i+1) + Ai | A(i+2) + …… + Ai | A(n),只需要统计每一位的贡献,就可以,嘴笨,看代码。
#include <cstdio>
#include <algorithm>
#define MAXN 100005
using namespace std;
long long ar[MAXN], sum[MAXN][65];
int judge(long long x, int y) {
if (x & (1<<y)) return 1;
return 0;
}
int main() {
int t = 1, n; scanf("%d", &t);
// freopen("data.txt", "r", stdin);
//freopen("2.txt", "w", stdout);
while (t--) {
scanf("%d", &n); long long ans = 0;
// printf("%d ", n);
for (int i = 0; i <= 17; i++) sum[0][i] = 0;
for (int i = 1; i <= n; i++) {
scanf("%lld", &ar[i]);
// printf("%d ", ar[i]);
for (int j = 0; j <= 17; j++) {
sum[i][j] = sum[i-1][j] + judge(ar[i], j);
}
ans += (n - 1)*ar[i];
}
// bit operator of '|'
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= 17; j++) {
long long num1 = sum[n][j] - sum[i][j];
long long num0 = n - i;
if (ar[i] & (1<<j)) ans += (1<<j)*num0*2;
else ans += (1<<j)*num1*2;
}
}
printf("%lld\n", ans);
}
return 0;
}