I - Wall Painting HDU - 4810 (位运算+找规律)

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 <= 10  3).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 10  6+3) from the first day to the n-th day.
Sample Input
4
1 2 10 1
Sample Output
14 36 30 8


题目说了一堆,意思就是给你n个数,让你输出n个数,其中第一个数是从上面n个数中取1个数,各种情况相加,

第二个数是从n个数中取2个数,先异或再加起来,以此类推。


从n个数中取k个数,先异或,再把C(n,k)种结果加起来,等同于
把n个数的二进制表示出来,统计每一位上1出现的次数,然后对每一位统计从n个二进制中取k个数取出1的个数为奇数的情况总数,对应总数乘以每一位的位权,得到最后结果。先打个表算组合数,然后按照上面的思路编,注意细节和技巧。

附一个细节:

对其中某一位,这一位有b[i]个1,这一天是第k天,一共有n天,则这一位对应的值为C(b[i],j)*C[n-b[i],k-j]%mod.其中j从1跑到k(取到k),每次j加2。


#include <iostream>
#include <stdio.h>
#include <string.h>
#define N 1050
#define mod 1000003
typedef long long LL;
using namespace std;
LL c[N][N];
void dabiao()
{
    for(int i=0;i<N;i++)
        c[i][0]=c[i][i]=1;
    for(int i=2;i<N;i++)
        for(int j=1;j<i;j++)
        c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
LL a[32];
int main()
{
    dabiao();
    int n;
    LL t;
    while(scanf("%d",&n)!=EOF)
    {   memset(a,0,sizeof(a));
        for(int i=0;i<n;i++)
        {   int j=0;
            cin>>t;
            while(t)//记录每个数据各个位上1的个数
            {
                if(t&1)
                a[j]++;
                j++;
                t>>=1;
            }
        }
        for(int k=1;k<=n;k++)//每一天的遍历
        {           LL sum=0;
                int t=1;
            for(int i=0;i<32;i++)//每一位的遍历
               {
                   LL ans=0;
                    for(int j=1;j<=k;j+=2)//确保取到的都是奇数
                        ans=(ans+c[a[i]][j]*c[n-a[i]][k-j]%mod)%mod;
                    sum=(sum+ans*t)%mod;
                    t=t*2;
               }
               if(k==1)
                cout<<sum;
               else
            cout<<" "<<sum;
        }cout<<endl;
    }

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值