Codeforces 895C - Square Subsets

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; }

 

posted @ 2017-11-28 15:53  Wisdom+.+  阅读(847)  评论(0编辑  收藏  举报