ZZULIOJ Problem 1893: 985的数学难题 【位运算】

 

1893: 985的数学难题

Time Limit: 2 Sec  Memory Limit: 128 MB
Submit: 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

hpu

 

 

郁闷,各种对拍,随机数,自己写数据,都和暴力的没有区别,就是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;
}

 


 

posted @ 2016-08-09 19:12  zprhhs  阅读(158)  评论(0编辑  收藏  举报
Power by awescnb