首页 > 代码库 > hdu 4810 Wall Painting (组合数学+二进制)
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 <cmath> 4 #include <queue> 5 #include <cstring> 6 #include <map> 7 #include <cstdlib> 8 #include <algorithm> 9 #define LL __int6410 #define INF 0x3f3f3f3f11 const int maxn = 1000+10;12 const int mo = 1000000+3;13 using namespace std;14 LL c[maxn][maxn], a[35], p[35]; //注意要用LL,中间计算会超int15 void init()16 {17 int i, j;18 memset(c, 0, sizeof(c));19 for(i = 0; i < maxn-5; i++)20 c[i][i] = c[i][0] = 1;21 for(i = 1; i < maxn-5; i++)22 for(j = 1; j < i; j++)23 c[i][j] = (c[i-1][j-1] + c[i-1][j])%mo;24 25 p[0] = 1;26 for(i = 1; i < 32; i++)27 p[i] = (2*p[i-1])%mo;28 }29 void cal(int x)30 {31 int cnt = 0;32 while(x)33 {34 if(x%2)35 a[cnt] ++;36 x /= 2;37 cnt ++; //这个不要放到上面数组中,不然会在数组的下标多加一个38 }39 }40 int main()41 {42 int n, i, j, k, x;43 LL tmp, ans;44 init();45 while(~scanf("%d", &n))46 {47 memset(a, 0, sizeof(a));48 for(i = 0; i < n; i++)49 {50 scanf("%d", &x);51 cal(x);52 }53 for(i = 1; i <= n; i++)54 {55 ans = 0;56 for(j = 0; j < 32; j++)57 {58 for(k = 1; k <= i; k += 2)59 {60 tmp = ((LL)(p[j]*c[a[j]][k]*c[n-a[j]][i-k]))%mo; //该位的数值 * 该位为1的个数选奇数个 * 为0的个数选空着的个数。61 ans += tmp;62 ans %= mo;63 }64 }65 if(i == n)66 printf("%I64d\n", ans);67 else68 printf("%I64d ", ans);69 }70 }71 return 0;72 }
hdu 4810 Wall Painting (组合数学+二进制)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。