题目链接http://acm.hdu.edu.cn/showproblem.php?pid=4810
解题思路:
记录下每个数的各个位上1个数的和,根据题意,异或要产生数值,必须是取基数个1,通过组合数学的方法,比如要在6个1里面取三个1,则取得方法有C(6,3),那么如何可以快速取得C(6,3)呢?通过杨辉三角形打表即可
#include <iostream> #include <cstdio> #include <cstring> using namespace std;#define P 1000003 int n, c[1005][1005], sum[40], a, ans[1005], t; // c[][]记录杨辉三角形
// sum[]记录每位上有多少个1;
// ans[]记录第k天有多少种方案 int main() {
// 杨辉三角形打表,记录C(m,n) for (int i =0; i <= 1000; i++) { c[i][0] = 1; c[i][i] = 1; } for (int i =1; i <= 1000; i++) { for (int j = 1; j < i; j++) { c[i][j] = (c[i - 1][j] % P + c[i-1][j-1] %P) %P; } } while (~scanf("%d", &n)) { memset(sum, 0, sizeof(sum)); memset(ans, 0, sizeof(ans));
// 将每位上有多少个1记录下来 for (int i= 0; i < n; i++) { int t; scanf("%d", &t); for (int j = 0; t;++j,t>>=1) { if (t%2) sum[j]++; //该位上有1; } } for (int k = 1; k <= n; k++) { for (int i = 0; i < 32; i++) { for (int j = 1; j <= sum[i] && j <= k; j += 2){ t = (long long )c[sum[i]][j]* c[n-sum[i]][k-j] %P*(1<<i)%P; ans[k] = (ans[k] + t) % P; } } } for (int k = 1; k <= n; k++) printf("%d%c", ans[k], k < n?' ':' '); } }