HDU 4810 Wall Painting(异或 +按位容斥)

直接不会,预估时间复杂度,对于C(n,m) 到规模为500就瞎了。当时也想算法应该接近常数级别的。

如果真的算必然跪。回头看了下解题报告。

话说比赛很喜欢考异或,“位”思想,组合问题

对于计算选取k个数字时候,分别计算各个位上可能出现的情况,然后计算各个位上的累加和。即便一个数字可由很多位组成但是每次计算一个位

记录每一位上1的个数(这里只需要32位),对于第i天,必须要选出奇数个1才能使该位异或结果位1,否则为0。我们来看样例,

4

1 2 10 1

这4个数的二进制表示分别为:

0001

0010

1010

0001

比如第2天的时候, 从4个中选出2个来做异或,第4位上只有1个1,所以有3中选法可以使得这一位异或之后结果为1,(也就是C(3,1) * C(1,1)),第3位的没有1,所以异或结果一定为0,第2位上又2个1,所以有4种选法,同理第一位上也是4种。

所以其结果就是 (1<<3)*C(3,1) + 0 * C(4,2) + (1<<1)*C(2,1)*C(2,1) + (1<<0)*C(2,1)*C(2,1)

注意细节:1.预处理C数组,注意范围,一个位上种类的选取是奇数但不能超过可选的数字。特别容易溢出。都用 long long

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define inf 0x3f3f3f3f
#define maxn 1100
#define MOD 1000003
using namespace std;
int N;
long long rem[32],c[maxn][maxn];
void init() {
        c[0][0] = c[1][0] = c[1][1] = 1;
        for (int i = 2; 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;
        }
        return ;
}
int main()
{init();
    while(~scanf("%d",&N)){
        memset(rem,0,sizeof(rem));
        for(int i=0;i<N;i++){
            int k;scanf("%d",&k);
            for(int j=0;j<32;j++)
                if( (1<<j)& k ) rem[j]++;
        }
        for(int i=1;i<=N;i++){
            long long ans=0;
            for(int j=0;j<32;j++){
                for(int k=1;k<=rem[j] && k<=i;k+=2)
                    ans=(ans+ ( c[N-rem[j]][i-k]* (c[rem[j]][k]* ( (1<<j)%MOD) )%MOD)%MOD)%MOD;
            }
            if(i==N) printf("%I64d\n",ans);
            else     printf("%I64d ",ans);
        }
    }
	return 0;
}
时间: 2025-01-04 14:23:15

HDU 4810 Wall Painting(异或 +按位容斥)的相关文章

HDU 4810 Wall Painting (位操作-异或)

OJ题目:click here~~ 题目分析:给n个数.从这n个数中选择i个数,共同拥有c(n , i)种情况.将每种情况中的i个数异或,将这c(n , i)个异或结果求和,就得到第i个输出结果,i属于[1  n]. 求x个数的异或,等于分别对x个数的同一二进制位进行异或,然后加权求和. 于是将n个数表示成二进制的形式.对于本题,32位就够. 由于,奇数个1的异或 = 1 , 偶数个1的异或 = 0 . 统计每位上1的个数 .然后对于第j个二进制位.枚举所选中的1的个数.加权求和,就可以得结果.

HDU 4810 Wall Painting【二进制+异或+暴力枚举】

给出n个数 求从这n个数取k个数异或,所有情况得到的值(Cnk个值(可能有些相同))全加起来的值是多少 k从1到n 输出这n个数 这题一开始想毫无思绪 也没有说这n个数的大概范围,想用背包来着本来 结果发现它是这么解的 就样例来说,把四个数1,2,10,1拆开,当前是取k个数 0001 0010 1010 0001 对第四位来说,如果某些方案是取k个数异或后为0,那么等于 0*方案数,这个我们可以不用管它 如果某些方案是取2个数异或后为1,那么等于1*方案数 可以看到第四位有1个1,那么异或为1

HDU - 4810 Wall Painting(组合数学)

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 bag

hdu 4810 Wall Painting

http://acm.hdu.edu.cn/showproblem.php?pid=4810 把每一个数转化二进制,然后统计n个数在每一位的1的个数.奇数个1异或才能得1,然后用组合数,计算. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int mod=1000003; 6 7 int n; 8 __int64 a[1100]

hdu 4810 Wall Painting (组合数学+二进制)

题目链接 下午比赛的时候没有想出来,其实就是int型的数分为30个位,然后按照位来排列枚举. 题意:求n个数里面,取i个数异或的所有组合的和,i取1~n 分析: 将n个数拆成30位2进制,由于每个二进制位异或后相加和原来的数异或相加是一样的,所以只需要对每一位累加计算,用组合数学取数就行了,奇数个异或得1,偶数个异或得0,再乘以自己的二进制位值,复杂度O(30*n*n) 1 #include <iostream> 2 #include <cstdio> 3 #include <

【bzoj4671】异或图(容斥+斯特林反演+线性基)

传送门 题意: 给出\(s,s\leq 60\)张图,每张图都有\(n,n\leq 10\)个点. 现在问有多少个图的子集,满足这些图的边"异或"起来后,这张图为连通图. 思路: 直接考虑判断图的连通不好判断,所以考虑枚举连通块来进行容斥. 定义\(f_i\)表示有\(i\)个连通块的答案,发现连通块这个东西也不好处理,我们只能处理出有多少个连通块,但无法确定每个连通块内部的连通关系. 定义\(g_i\)为至少有\(i\)个连通块的方案数,那么就有关系式:\(\displaystyle

HDU 1796 How many integers can you find 容斥入门

How many integers can you find Problem Description Now you get a number N, and a M-integers set, you should find out how many integers which are small than N, that they can divided exactly by any integers in the set. For example, N=12, and M-integer

HDU 5155 Harry And Magic Box(组合数学+容斥)

Problem Description One day, Harry got a magical box. The box is made of n*m grids. There are sparking jewel in some grids. But the top and bottom of the box is locked by amazing magic, so Harry can't see the inside from the top or bottom. However, f

hdu 1796 How many integers can you find 容斥定理

How many integers can you find Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem Description Now you get a number N, and a M-integers set, you should find out how many integers which are small than N, that t