您的位置:首页 > 大数据 > 人工智能

hdu4810 Wall Painting

2015-08-19 14:58 387 查看
题目意思就是给定n(≤1000)个整数,要求输出对于所有整数k(1..n),该整数集合的所有元素个数为k的子集其元素的异或的和对M取模的值。

考虑所有包含于原集合的k子集的个数,当n=1000, k = 500的时候,(n, k)非常之大。

显然单个考虑某一k子集对和的贡献不是一个合适的切入点。

再仔细看看题目,要求的到底的是什么。

给定集合S, #(S) = n, 给定 k ≤ n, 求∑f(A) % M, 其中A ⊆ S,且 #(A) = k, f(A) = ^A[i], (A[i] ∈ A)。

我们用长度足够大(记为len)的二进制数重写整数(对于本题长度大于32即可),假设整数a = str_A(binary form)

那么a^b = str_A ^ str_B = ∑(1 << i) * ((str_A[i] + str_B[i]) % 2) (i < len)。

也就是说,依次考察二进制串的每一位,若两个整数在该位上1的个数之和为奇数,则向两数异或中该位置贡献1,否则贡献0。

则f(A) = ^A[i] = ^ str_A[i] = ∑(1 << j) * (∑str_A[i][j] % 2) (j < len)。

到这里距离答案只有一步之遥了。

下面的问题在于怎么求∑f(A)。

这是一个求和,我们把j放在最外层循环。

那么我们有∑f(A)

= ∑(∑(1 << j) * (∑str_A[i][j] % 2)) (j < len)

= (1 << j) * ∑(∑str_A[i][j] % 2) ( j < len, str_A[i] 代表属于集合A中一个整数对应的二进制串,#(A) = k )

我们现在只考虑第j位上的情况。

我们知道每一个k子集最多向j位上贡献1,我们考虑所有k子集向j位上贡献多少。

假设原集合S中的数在第j位上依次是c[0], c[1], ..., c[n - 1], 其中c[i]非0即1。

也就是我们向这n个数中取k个数,数一数取得的数中1有奇数个还是偶数个,若为奇数个则贡献1,否则贡献0。

我们假设n个数中1的个数为p, 0的个数为 n - p。

那么所有k子集在该位上的贡献值应该是(p, 1) * (n - p, k - 1) + (p, 3) * (n - p, k - 3) +...

具体过程见代码。

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

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef __int64 LL;

const int maxn = 1e3 + 10;
const int mod = 1e6 + 3;

int n;
int s[maxn];
LL c[maxn][maxn];
int ans[maxn];

void init(){
memset(c, 0, sizeof c);
c[0][0] = c[1][0] = c[1][1] = 1;
for(int i = 2; i <= 1000; i++){
c[i][0]= c[i][i] = 1;
int mid = i / 2;
for(int j = 1; j <= mid; j++){
c[i][i - j] = c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
}
}

void solve(){
memset(ans, 0, sizeof ans);
for(int i = 30; i >= 0; i--){
int f = 1 << i;
int cnt = 0;
for(int j = 0; j < n; j++) if(s[j] & f) ++cnt;
f %= mod;
for(int j = 1; j <= n; j++){
for(int k = 1; k <= cnt && k <= j; k += 2){
ans[j - 1] += ((c[cnt][k] * c[n - cnt][j - k]) % mod * f) % mod;
ans[j - 1] %= mod;
}
}
}
printf("%d", ans[0]);
for(int i = 1; i < n; i++) printf(" %d", ans[i]);
printf("\n");
}

int main(){
init();
while(~scanf("%d", &n)){
for(int i = 0; i < n; i++) scanf("%d", &s[i]);
solve();
}
return 0;
}

/*
0001
0010
1010
0001
*/


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: