【異或】HDU - 4810 Wall Painting

題目鏈接

Description

給定n個數,第 i 天選取 i 個數,使這 i 個數相異或,對這一天所有可能的組合 異或後 的值進行求和,輸出從1到n天的結果

Solution

首先0和1異或是不會影響結果的,只有1和1異或並且1的個數是奇數的時候纔會對結果產生影響,所以考慮將每個數轉換成二進制,統計每一位上的1的個數,利用組合數學解決。(參考異或的性質

因此,枚舉所有二進制位,計算出每個第 j 位上1的個數 bit[j],枚舉 1~k 之間所有的奇數(1,3,5,7……),利用組合數求出各種取法的和然後乘上權值 1 << j。

例如對於一些二進制數,第0位上一共有4個1,第1位上一共有4個1,第2位上一共有0個1,第3位上一共有3個1,如下所示:
3 2 1 0 (二進制位)
3 0 4 4 (1的個數)
結果就是把最後的每一位上的數轉換出來 ans1 = 3pow(2,3) + 0pow(2,2)+ 4pow(2,1) + 4pow(2,0) = 36.
那麼這個過程轉換爲公式就是:

ans[i]+=(C[bit[j]][k]C[nbit[j]][ik])(1&lt;&lt;j)ans[ i ] += (C[ bit[j] ][ k ] * C[ n - bit[j] ][ i - k ] ) * ( 1 &lt;&lt; j )

其中ans[ i ] 代表選取 i 個數的最後結果,C[ bit[j] ][ k ] 爲在 bit[j] 個1中選取k個1, k 爲奇數,C[ n - bit[j] ][ i - k ] 爲在 n-bit[j] 個0中選取 i-k 個0

他們的乘積就是每一位上可能的組合的數目,然後再乘這一位上的值(1 << j)就是這一位上的結果,然後把每一位上的加起來就行了。

Code

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define fi first
#define se second
#define fopen freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);
#define mst(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const int Mod = 1e6 + 3;
const int MaxN = 1e3 + 5;

int c[MaxN][MaxN];
int a[MaxN], bit[MaxN];
int n;

void get_C() {
    mst(c, 0);
    c[0][0] = 1;
    for(int i = 1; i < MaxN; i++) {
        c[i][0] = 1;
        for(int j = 1; j <= i; j++)
            c[i][j] = (c[i-1][j] + c[i-1][j-1]) % Mod;
    }
}

void get_bit() {
    mst(bit, 0);
    for(int i = 1; i <= n; i++) {
        for(int j = 0; j < 32; j++) {
            if(a[i] & (1 << j)) bit[j]++;
        }
    }
}

int main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); 

    get_C();
    while(cin >> n) {
        for(int i = 1; i <= n; i++) cin >> a[i];
        get_bit();
        for(int i = 1; i <= n; i++) {
            LL ans = 0LL;
            for(int j = 0; j < 32; j++) {
                for(int k = 1; k <= bit[j] && k <= i; k += 2) {
                    ans += ((LL)c[bit[j]][k] * c[n-bit[j]][i-k]) % Mod * ((1 << j) % Mod);
                    ans %= Mod;
                }
            }
            i == n ? cout << ans % Mod << endl : cout << ans % Mod << " ";
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章