zoukankan      html  css  js  c++  java
  • Codeforces 895C Square Subsets:状压dp【组合数结论】

    题目链接:http://codeforces.com/problemset/problem/895/C

    题意:

      给你n个数a[i]。(n <= 10^5, 1 <= a[i] <= 70)

      问你有多少非空子集s,使得 ∏(s[i])为完全平方数。

    题解:

      由于a[i] <= 70,而70以内的质数只有19个,显然可以状压。

     

      由于一个数是完全平方数的条件是:它的每种质因子的指数为偶数

      所以先处理出对于每个a[i],它的所有质因子指数的奇偶性f[i]。

      对于f[i]的每一位,0表示它的质因子prime[i]的指数为偶,1代表为奇数。

      另外由于n比较大,所以dp中状态不能是“当前考虑到a[i]”,而应该是“当前考虑到数字i”。

      所以之前要统计一下为数字i的a[j]的个数cnt[i]。(x <= 70)

      然后开始状压。

      表示状态:

        dp[i][state]表示当前考虑到数字i,子集和的质因子指数的奇偶性为state,此时的子集方案数

      找出答案:

        由于1到70的所有数都会考虑一遍,且最终的子集和的质因子的指数都应该为偶数

        另外由于要求是非空子集,最终答案要-1

        所以ans = dp[71][0] - 1

      如何转移:

        对于数字i来说,如果cnt[i] == 0,则直接将所有dp[i][state]复制到dp[i+1][state]即可。

        否则分两种情况:数字i选偶数个 or 奇数个。选偶数个i不会影响子集和质因子指数的奇偶性,而奇数个会影响。

        (1)偶数个:dp[i+1][state] += dp[i][state] * C(n,m),其中m = 0,2,4,6,8...

        (2)奇数个:dp[i+1][state^f[i]] += dp[i][state] * C(n,m),其中m = 1,3,5,7,9...

        有一个结论:∑ C(n,{0,2,4,6,8...}) = ∑ C(n,{1,3,5,7,9...}) = 2^(n-1)

        之前预处理所有p[i] = 2^i % MOD即可。

      边界条件:

        dp[1][0] = 1

        others = 0

    AC Code:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define MAX_N 100005
     5 #define MAX_A 75
     6 #define MAX_S 550000
     7 #define MOD 1000000007
     8 
     9 using namespace std;
    10 
    11 const int prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67};
    12 
    13 int n;
    14 int p[MAX_N];
    15 int f[MAX_A];
    16 int cnt[MAX_A];
    17 int dp[MAX_A][MAX_S];
    18 
    19 void read()
    20 {
    21     cin>>n;
    22     memset(cnt,0,sizeof(cnt));
    23     int a;
    24     for(int i=1;i<=n;i++)
    25     {
    26         cin>>a;
    27         cnt[a]++;
    28     }
    29 }
    30 
    31 void cal_f()
    32 {
    33     memset(f,0,sizeof(f));
    34     for(int i=1;i<=70;i++)
    35     {
    36         int t=i;
    37         for(int j=0;j<19;j++)
    38         {
    39             while(t%prime[j]==0)
    40             {
    41                 f[i]^=(1<<j);
    42                 t/=prime[j];
    43             }
    44         }
    45     }
    46 }
    47 
    48 void cal_p()
    49 {
    50     p[0]=1;
    51     for(int i=1;i<MAX_N;i++) p[i]=(p[i-1]<<1)%MOD;
    52 }
    53 
    54 void cal_dp()
    55 {
    56     memset(dp,0,sizeof(dp));
    57     dp[1][0]=1;
    58     for(int i=1;i<=70;i++)
    59     {
    60         if(!cnt[i])
    61         {
    62             for(int state=0;state<(1<<19);state++)
    63             {
    64                 dp[i+1][state]=dp[i][state];
    65             }
    66         }
    67         else
    68         {
    69             for(int state=0;state<(1<<19);state++)
    70             {
    71                 if(dp[i][state])
    72                 {
    73                     dp[i+1][state]=(dp[i+1][state]+(long long)dp[i][state]*p[cnt[i]-1])%MOD;
    74                     dp[i+1][state^f[i]]=(dp[i+1][state^f[i]]+(long long)dp[i][state]*p[cnt[i]-1])%MOD;
    75                 }
    76             }
    77         }
    78     }
    79 }
    80 
    81 void work()
    82 {
    83     cal_f();
    84     cal_p();
    85     cal_dp();
    86     cout<<dp[71][0]-1<<endl;
    87 }
    88 
    89 int main()
    90 {
    91     read();
    92     work();
    93 }
  • 相关阅读:
    Leetcode 70 Climbing Stairs 递推
    Leetcode 83 Remove Duplicates from Sorted List 链表
    Leetcode 328 Odd Even Linked List 链表
    Leetcode 206 Reverse Linked List 链表
    Spring中注解
    SpringMVC配置文件
    java设计模式----单例模式
    java设计模式----工厂方法模式
    java设计模式----装饰者模式
    java设计模式----观察者模式
  • 原文地址:https://www.cnblogs.com/Leohh/p/8465778.html
Copyright © 2011-2022 走看看