#异或# HDU - 4810 Wall Painting

版权声明:本文为博主原创文章,转载清注明出处 https://blog.csdn.net/Jasmineaha/article/details/81535878

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

Description:

给出 N 和 k,第 k(1 <= k <= N) 天从 n 个数个中任意选择 k 个数进行异或,再把所有可能的异或值进行求和,依次输出。

Solution:

异或的性质:对于每一个二进制位只有当1的个数为奇数时,异或后该位才能为1(1 ^ 1 = 0,1 ^ 0 = 1)。
(参考博客:https://blog.csdn.net/Jasmineaha/article/details/81412711

因此,我们可以枚举所有二进制位,计算出每个第 j 位上1的个数 bit[j],枚举 1~k 之间所有的奇数(1,3,5,7……),利用组合数求出各种取法的和然后乘上权值 1 << j。

例如对于一些二进制数,第0位上一共有4个1,第1位上一共有4个1,第2位上一共有0个1,第3位上一共有3个1,如下所示:
3 2 1 0 (二进制位)
3 0 4 4 (1的个数)
结果就是把最后的每一位上的数转换出来 ans1 = 3pow(2,3) + 0pow(2,2)+ 4pow(2,1) + 4pow(2,0) = 36.
那么这个过程转换为公式就是:
ans[ i ] += (C[ bit[j] ][ k ] * C[ n - bit[j] ][ i - k ] ) * ( 1 << j )
ans[ i ] 代表选取 i 个数的最后结果;C[ bit[j] ][ k ] 为在 bit[j] 个1中选取k个1,其中 k 为奇数;C[ n - bit[j] ][ i - k ] 为在 n-bit[j] 个0中选取 i-k 个0;
他们的乘积就是每一位上可能的组合的数目,然后再乘这一位上的值(1 << j)就是这一位上的结果,然后把每一位上的加起来就行了。

Code:

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define fi first
#define se second
#define fopen freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);
#define mst(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const int Mod = 1e6 + 3;
const int MaxN = 1e3 + 5;

int c[MaxN][MaxN];
int a[MaxN], bit[MaxN];
int n;

void get_C() {
    mst(c, 0);
    c[0][0] = 1;
    for(int i = 1; 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;
    }
}

void get_bit() {
    mst(bit, 0);
    for(int i = 1; i <= n; i++) {
        for(int j = 0; j < 32; j++) {
            if(a[i] & (1 << j)) bit[j]++;
        }
    }
}

int main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); 

    get_C();
    while(cin >> n) {
        for(int i = 1; i <= n; i++) cin >> a[i];
        get_bit();
        for(int i = 1; i <= n; i++) {
            LL ans = 0LL;
            for(int j = 0; j < 32; j++) {
                for(int k = 1; k <= bit[j] && k <= i; k += 2) {
                    ans += ((LL)c[bit[j]][k] * c[n-bit[j]][i-k]) % Mod * ((1 << j) % Mod);
                    ans %= Mod;
                }
            }
            i == n ? cout << ans % Mod << endl : cout << ans % Mod << " ";
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Jasmineaha/article/details/81535878