zoukankan      html  css  js  c++  java
  • hdu4810 Wall Painting

    题目意思就是给定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

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 
     5 using namespace std;
     6 typedef __int64 LL;
     7 
     8 const int maxn = 1e3 + 10;
     9 const int mod = 1e6 + 3;
    10 
    11 int n;
    12 int s[maxn];
    13 LL c[maxn][maxn];
    14 int ans[maxn];
    15 
    16 void init(){
    17     memset(c, 0, sizeof c);
    18     c[0][0] = c[1][0] = c[1][1] = 1;
    19     for(int i = 2; i <= 1000; i++){
    20         c[i][0]= c[i][i] = 1;
    21         int mid = i / 2;
    22         for(int j = 1; j <= mid; j++){
    23             c[i][i - j] = c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
    24         }
    25     }
    26 }
    27 
    28 void solve(){
    29     memset(ans, 0, sizeof ans);
    30     for(int i = 30; i >= 0; i--){
    31         int f = 1 << i;
    32         int cnt = 0;
    33         for(int j = 0; j < n; j++) if(s[j] & f) ++cnt;
    34         f %= mod;
    35         for(int j = 1; j <= n; j++){
    36             for(int k = 1; k <= cnt && k <= j; k += 2){
    37                 ans[j - 1] += ((c[cnt][k] * c[n - cnt][j - k]) % mod * f) % mod;
    38                 ans[j - 1] %= mod;
    39             }
    40         }
    41     }
    42     printf("%d", ans[0]);
    43     for(int i = 1; i < n; i++) printf(" %d", ans[i]);
    44     printf("
    ");
    45 }
    46 
    47 int main(){
    48     init();
    49     while(~scanf("%d", &n)){
    50         for(int i = 0; i < n; i++) scanf("%d", &s[i]);
    51         solve();
    52     }
    53     return 0;
    54 }
    55 
    56 /*
    57 0001
    58 0010
    59 1010
    60 0001
    61 */
    View Code
  • 相关阅读:
    四十一:HTML5之HTML5属性变化之input新增类型
    四十:HTML5之HTML5标签变化之删除的标签和重定义的标签
    三十九:HTML5之HTML5标签变化之新增的其他标签和简单的使用示例
    三十八:HTML5之HTML5标签变化之新增的web应用标签和简单的使用示例
    三十七:HTML5之HTML5标签变化之新增的多媒体标签和简单的使用示例
    三十六:HTML5之HTML5标签变化之新增的结构标签和简单的使用示例
    三十五:布局之布局小案例
    python初识-day2
    Python初识-day1
    leetcode maximum product subarray
  • 原文地址:https://www.cnblogs.com/astoninfer/p/4742232.html
Copyright © 2011-2022 走看看