Codeforces 895C - Square Subsets
思路:状压dp。
每个数最大到70,1到70有19个质数,给这19个质数标号,与状态中的每一位对应。
状压:一个数含有这个质因子奇数个,那么他状态的这一位是1,一个数含有这个这个质因子偶数个,那么状态的这一位是0。
那么如果一个数是平方数,那么这个数的状态每一位都是0,即状态为0。
状态转移见代码。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) const int N=1e5+5; const int MOD=1e9+7; int a[N]; int cnt[75]; int dp[75][(1<<19)+5]; int s[75]; int prime[19]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67}; int _2p[N]; int main() { ios::sync_with_stdio(false); cin.tie(0); for(int i=1;i<=70;i++) { int t=i; for(int j=0;j<19;j++) { while(t%prime[j]==0)t/=prime[j],s[i]^=(1<<j); } } _2p[0]=1; for(int i=1;i<N;i++)_2p[i]=(_2p[i-1]*2)%MOD; int n; cin>>n; for(int i=1;i<=n;i++)cin>>a[i],cnt[a[i]]++; dp[0][0]=1; for(int i=1;i<=70;i++) { if(!cnt[i]) { for(int j=0;j<(1<<19);j++) dp[i][j]=dp[i-1][j]; } else { for(int j=0;j<(1<<19);j++) { dp[i][j^s[i]]=((ll)dp[i][j^s[i]]+(ll)_2p[cnt[i]-1]*dp[i-1][j])%MOD;//从cnt[i]个数个选奇数个,C(n,1)+C(n,3)+...=2^(n-1) dp[i][j]=((ll)dp[i][j]+(ll)_2p[cnt[i]-1]*dp[i-1][j])%MOD;//从cnt[i]个数个选偶数个,C(n,0)+C(n,2)*C(n,4)+...=2^(n-1) } } } cout<<(dp[70][0]-1)%MOD<<endl;//减去0的情况
return 0; }