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

hdoj 4810 Wall Painting 【思维 + 组合数学】

2015-11-15 11:36 507 查看

Wall Painting

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 2182    Accepted Submission(s): 684


Problem 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 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 <= 103).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 106 +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次操作。对第i次操作,要求你从n个数里面任选i个数,用这i个数异或得到一个新数,并把所有新数相加(可以重复加)。对每次操作,输出新数相加之和。

思路:考虑二进制中的1,只有奇数个同位的1 相异或 才能使该进制位的1不丢失。这样考虑每个二进制位上的1对结果做出的贡献,然后累加贡献值就可以了。

如在第j位有num[j]个1,现在要从这n个数里面选i个数异或,对第j位的1来说,我们只需要考虑1不丢失的所有方案

=从num[j]个1里面选奇数个1(这里设选k个),再从n-num[j]里面选出剩下i-k个 = C(num[j], k)*C(n-num[j], i-k)

得到贡献值 = 方案数 * 该二进制位上1的价值 = C(num[j], k) * C(n-num[j], i-k) * (1<<j)

时间复杂度O(n*n*35)。

一开始直接用阶乘去除,WA好几次。真是犯二了,把逆元忘了,换种写法就KO了。。。

AC代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define MAXN (100000+10)
#define MAXM (50000000)
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while(a--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 1000003
#define LL long long
#define lson o<<1, l, mid
#define rson o<<1|1, mid+1, r
#define ll o<<1
#define rr o<<1|1
using namespace std;
int num[40];
LL C[1010][1010];
void getC()
{
for(int i = 0; i <= 1000; i++)
C[i][0] = 1;
for(int i = 1; i <= 1000; i++)
for(int j = 1; j <= i; j++)
C[i][j] = (C[i-1][j] + C[i-1][j-1]) % MOD;
}
int main()
{
getC();
int n;
while(Ri(n) != EOF)
{
CLR(num, 0);
for(int i = 1; i <= n; i++)
{
LL a; Rl(a);
for(int j = 0; j <= 35; j++)
if(a & (1LL<<j))
num[j]++;
}
for(int i = 1; i <= n; i++)
{
LL cnt = 0;
for(int j = 0; j <= 35; j++)//第j位的1
{
if(num[j] == 0) continue;
for(int k = 1; k <= i && k <= num[j]; k+=2)//选k个1 k为奇数时异或才加
{
if(n-num[j] >= i-k)
{
cnt += C[num[j]][k] * ((1LL<<j) % MOD) % MOD * C[n-num[j]][i-k] % MOD;
cnt %= MOD;
}
}
}
if(i > 1)
printf(" ");
printf("%lld", cnt);
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: