首页 > 其他 > 详细

状压dp+数论——cf895C好题!

时间:2020-02-11 16:34:23      阅读:61      评论:0      收藏:0      [点我收藏+]

把模数写成了1e9+9,气死我了

/*
1-70里只有19个质数,首先考虑状压dp
第i个质数出现奇数次,那么第i位为1,反之为0
每个数在质因子分解后都可以得到一个对应的mask 
dp[i][s]表示当前选的数是i,且其状态为s时的方案数
    那么选择偶数个i对s的状态无影响,有C(cnti,0)+C(cnti,2)..=2^(cnti-1)(二项式定理) 种方案 
    选择偶数个i对s的影响是s^mask[i],也有 2^(cnti-1)种方案 
    
    转移方程
        dp[i][s]+=dp[i-1][s^mask[i]] * p2[cnt[i]-1] 选奇数个i 
        dp[i][s]+=dp[i-1][s] * p2[cnt[i]-1] 
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define mod 1000000007
 
ll primes[20]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67};
ll n,cnt[72],a[200005],dp[2][1<<20];
ll mask[72],p2[200005];
 
int getmask(int x){
    int res=0;
    for(int i=0;i<=18;i++){
        int flag=0;
        while(x%primes[i]==0)
            x/=primes[i],flag^=1;
        if(flag)res|=(1<<i);
    }
    return res;
}
 
int main(){
    cin>>n;
    p2[0]=1;
    for(int i=1;i<=200000;i++)p2[i]=p2[i-1]*2%mod;
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]),cnt[a[i]]++;
    for(int i=1;i<=70;i++)mask[i]=getmask(i);
    
    dp[0][0]=1;
    
    int cur=0;
    for(int i=1;i<=70;i++){
        if(cnt[i]==0)continue;
        cur^=1;
        memset(dp[cur],0,sizeof dp[cur]);
        for(int s=0;s<(1<<19);s++){
            dp[cur][s]=(dp[cur][s]+dp[cur^1][s^mask[i]]*p2[cnt[i]-1]%mod)%mod;
            dp[cur][s]=(dp[cur][s]+dp[cur^1][s]*p2[cnt[i]-1]%mod)%mod; 
        }
    }
    
    cout<<(dp[cur][0]-1+mod)%mod<<\n;
}

 

状压dp+数论——cf895C好题!

原文:https://www.cnblogs.com/zsben991126/p/12295445.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!