HDU-4810 Wall Paiting 位運算 , 組合
阿新 • • 發佈:2020-08-25
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' : ' '); } } }