Loading

HDU-4810 Wall Paiting 位运算 , 组合

HDU-4810 Wall Paiting

题意

给定\(n\) 个数,分别输出\(i\) 个答案,每个答案表示从\(n\) 个数中选择\(C_n^i\) 组数,计算这组数的异或和,再将这\(C_n^i\) 组数的和相加。

分析

由于是异或,各位之间不相互影响,我们考虑每个数每一位对答案的贡献,考虑二进制的第\(i\) 位,如果第\(i\) 位对答案有贡献,也就是\(1\) ,那么这一位一定是由奇数个1异或得到,所以我们其实只要统计第\(i\) 位为\(1\) 的个数,对这个排列组合即可。注意还要乘上\(2^i\)

代码

ll C[1005][1005];
int num[35];
void get_C()
{
    C[0][0] = 1;
    for (int i = 1; i <= 1003; i++)
    {
        C[i][0] = 1;
        for (int j = 1; j <= i; j++)
            C[i][j] = C[i - 1][j] + C[i - 1][j - 1], C[i][j] %= MOD;
    }
}

int main() {
    int n;
    get_C();
    while (~scanf("%d", &n)) {
        memset(num, 0, sizeof num);
        for (int i = 0; i < n; i++) {
            ll x = readint();
            for (int j = 32; j >= 0; j--)
                if ((1ll << j) & x) num[j]++;
        }
        for (int i = 1; i <= n; i++) {
            ll sum = 0;
            for (int j = 32; j >= 0; j--) {
                ll res = 0;
                for (int k = 1; k <= i; k += 2) {
                    res += C[num[j]][k] * C[n - num[j]][i - k] % MOD;
                    res %= MOD;
                }
                sum = (ksm(2, (ll)j, MOD) * res % MOD + sum) % MOD;
            }
            Put(sum);
            putchar(i == n ? '\n' : ' ');
        }
    }
}
posted @ 2020-08-25 21:45  MQFLLY  阅读(87)  评论(0编辑  收藏  举报