SPOJ:EXPOR

来源:互联网 发布:钢丝杨氏模量实验数据 编辑:程序博客网 时间:2024/06/05 15:09

点击打开题目 

题意

给出n个数A1, A2...,AN, 任意选择两个数i,j(1 <= i < j <= N),问Ai|Aj的期望值是多少。

以既约分数的形式输出。

数据

1 <= T <= 10, 2 <= N <= 1e5, 0 <= Ai < 2^31

输入

2

2

0 0

3

1 2 3

输出

0/1

3/1

思路

可选择的总方案数为n*(n-1)/2,若我们能算出所有方案的答案总和,约分后即为答案。
暴力枚举是n^2不可行,一个常见的做法是对每一位分别考虑答案。
假设前i-1个数第j位为1的个数为cnt,当第i个数的第j位为1时,这一位对答案的贡献为(1<<j)*(i-1).
否则对答案的贡献为cnt*(1<<j),复杂度O(nlogn).
分子可能会大于long long, 这题unsigned long long 可以过。


代码:

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;typedef unsigned long long llu;const int maxn = 1e5+5;llu rec[35];int main(void){    llu t, n;    cin >> t;    while(t--)    {        scanf("%llu", &n);        memset(rec, 0, sizeof(rec));        llu ans = 0;        for(int i = 1; i <= n; i++)        {            llu t;            scanf("%llu", &t);            for(int j = 0; j < 32; j++)            {                int tmp = (t>>j)&1;                if(tmp) ans += (llu)(i-1)*((llu)1<<j);                else ans += (llu)rec[j]*((llu)1<<j);                rec[j] += tmp;            }        }        llu gcd = __gcd(ans, n*(n-1)/2);        printf("%llu/%llu\n", ans/gcd, n*(n-1)/2/gcd);    }    return 0;}