2013南京站I題||hdu4810 二進位制列舉

life4711發表於2014-09-13

http://acm.hdu.edu.cn/showproblem.php?pid=4810

Problem Description
Ms.Fang loves painting very much. She paints GFW(Great Funny Wall) every day. Every day before painting, she produces a wonderful color of pigments by mixing water and some bags of pigments. On the K-th day, she will select K specific bags of pigments and mix them to get a color of pigments which she will use that day. When she mixes a bag of pigments with color A and a bag of pigments with color B, she will get pigments with color A xor B.
When she mixes two bags of pigments with the same color, she will get color zero for some strange reasons. Now, her husband Mr.Fang has no idea about which K bags of pigments Ms.Fang will select on the K-th day. He wonders the sum of the colors Ms.Fang will get with different plans.

For example, assume n = 3, K = 2 and three bags of pigments with color 2, 1, 2. She can get color 3, 3, 0 with 3 different plans. In this instance, the answer Mr.Fang wants to get on the second day is 3 + 3 + 0 = 6.
Mr.Fang is so busy that he doesn’t want to spend too much time on it. Can you help him?
You should tell Mr.Fang the answer from the first day to the n-th day.
 

Input
There are several test cases, please process till EOF.
For each test case, the first line contains a single integer N(1 <= N <= 103).The second line contains N integers. The i-th integer represents the color of the pigments in the i-th bag.
 

Output
For each test case, output N integers in a line representing the answers(mod 106 +3) from the first day to the n-th day.
 

Sample Input
4 1 2 10 1
 

Sample Output
14 36 30 8
解題思路:

                 一開始拿到這個題感覺有點摸不著頭腦,最笨的方法是列舉出所有的種類一個一個的進行異或,但是馬上就想到這個方法根本就行不通,先不說超時的問題,就是組合數在longlong範圍內就根本不可能取得到。    

                似乎這個題沒有什麼解法了,但是仔細想想,根異或的特性,對於每一個二進位制位我們只有當1的個數為奇數的時候才可能通過異或在該位得到1。因此,我們可以列舉所有二進位制位,計算出每個二進位制位上1的個數k,我們列舉1~k之間所有的奇數(1,3,5,7……),利用組合數求出各種取法的和然後乘上權值1<<i。

               想到這裡,緊接著又出現了一個新的問題,就是求得的和是否等於所求呢?只是列舉的單個位數,我們在取得時候可是要整取的啊?可以這樣想,在整取的過程中,把所有的情況全列舉出來之後做異或時還是要各個位單獨異或,相互之間沒有影響,最後在做完還是要加起來。傳統的過程與我們的做法唯一不同的是:他是把一個數的各個二進位制位計算出後相加從而得到一個新的數,然後和其他情況計算出的數進行相加取和。而我們是把所有情況中相同的二進位制位先相加,然後在對所有的二進位制位進行求和。過程不一樣,其結果是一致的。問題分析到這裡基本上就可以收尾了,下面就是程式碼實現了

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long LL;
const int MOD=1000003;
const int N=1005;

int n,c[N][N],a[N];
int ans[N];

void init()//預處理,先求出組合數
{
    memset(c,0,sizeof(c));
    for(int i=0;i<N;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;
    }
    /*for(int i=0;i<=10;i++)
    {
        for(int j=0;j<=i;j++)
            printf("%d ",c[i][j]);
        printf("\n");
    }*/
}

void get(int n)//統計各個二進位制位上有多少個1
{
    for(int i=0;i<32;i++)
    {
        if(n&(1<<i))
            a[i]++;
    }
}
int main()
{
    init();
    while(~scanf("%d",&n))
    {
        int temp;
        memset(a,0,sizeof(a));
        for(int i=0;i<n;i++)
        {
            scanf("%d",&temp);
            get(temp);
        }
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=n;i++)//1~n的所有情況
            for(int j=0;j<32;j++)//所有的二進位制位。題目給出數最大不過1000000+3,32位足矣
                for(int k=1;k<=a[j]&&k<=i;k+=2)//從1~a[j]列舉出所有的奇數情況,並且還要保證不能超過i
                    ans[i]=(ans[i]+(LL)c[a[j]][k]*c[n-a[j]][i-k]%MOD*(1<<j%MOD)%MOD)%MOD;//這裡的中間過程會爆掉int,需要強制轉換一下子
        for(int i=1;i<=n;i++)
            printf(i==n?"%d\n":"%d ",ans[i]);
    }
    return 0;
}



相關文章