題目連結: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 }