CF 895C. Square Subsets DP(状压,平方数)

来源:互联网 发布:什么叫矩阵测光 编辑:程序博客网 时间:2024/05/18 16:55
题意:给出长度为n的序列a,问序列a有多少个子集,其乘积为平方数.
n<=1e5,a[i]<=70.


平方数其素因子的幂为偶数,70内有19个素因子
设状态为19位二进制 第i位为0表示 x唯一分解中:第i个素因子的幂为偶数. 1代表幂为奇数.
若一个一个加入数更新状态 则TLE  因为改变的状态只分加入偶数次和奇数次. 

所以保存每个数的个数. 加入奇/偶数次的方案都为2^(cnt[x]-1) 偶数在扣掉空集,暴力更新状态即可 O( (1<<19) *70*2)

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N=1e5+5,M=75,mod=1e9+7;int n,x,cnt[M],st[M];int pri[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67};ll dp[2][1<<20],pw2[N];void init(){for(int j=2;j<=70;j++){int x=j;for(int i=0;i<20&&x!=1;i++){while(x%pri[i]==0)x/=pri[i],st[j]^=(1<<i);}}pw2[0]=1;for(int i=1;i<N;i++)pw2[i]=(pw2[i-1]*2ll)%mod;}int main(){init();scanf("%d",&n);int mx=0;for(int i=0;i<n;i++){scanf("%d",&x);cnt[x]++;mx=max(mx,x);}dp[0][0]=1;int cur=1;for(int i=1;i<=70;i++){if(cnt[i]==0)continue; for(int s=0;s<(1<<20);s++){if(dp[cur^1][s]==0)continue;int nxt=s ^ st[i];int m=cnt[i]-1;if(nxt==s){dp[cur][s]=(dp[cur^1][s]*(pw2[m+1]-1)%mod)%mod;continue;}dp[cur][nxt]=(dp[cur][nxt]+(dp[cur^1][s]*pw2[m])%mod)%mod; dp[cur][s]=(dp[cur][s]+(dp[cur^1][s]*(pw2[m]-1))%mod)%mod; }for(int s=0;s<(1<<20);s++)dp[cur][s]=(dp[cur][s]+dp[cur^1][s])%mod;cur^=1;//resetfor(int s=0;s<(1<<20);s++)dp[cur][s]=0;}cout<<dp[cur^1][0]-1<<endl;return 0;} 



原创粉丝点击