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 ", ans); } return 0; }