zoukankan      html  css  js  c++  java
  • C. Square Subsets 题解(状压dp)

    题目链接

    题目思路

    首先呢,状压\(dp\)还是可以想到的

    发现只有20个质数,设\(dp[i][j]\)表示前\(i\)个数状态为\(j\)的方案数

    但是时间复杂度明显不允许这样复杂为\(n*2^{20}\)

    考虑优化

    发现数字非常少只有70个,而且对于最后状态的影响,大小为\(i\)的数的个数只和奇偶有关

    那么我们设\(dp[i][j]\)表示选取了大小\(1-i\)的数中状态为\(j\)的方案数

    注意\(c(n,0)+c(n,2)+c(n,4)...=c(n,1)+c(n,3)+c(n,5)...=2^{n-1}\)

    代码

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define debug cout<<"I AM HERE"<<endl;
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    #define  pii pair<long long,long long >
    //typedef pair<long long,long long > pii
    const int maxn=1e5+5,inf=0x3f3f3f3f,mod=1e9+7;
    const double eps=1e-6;
    const ll INF=0x3f3f3f3f3f3f3f3f;
    int n;
    int a[maxn];
    int isprime[80];
    int tot;
    int msk[80];
    ll pw[maxn];
    int cnt[80];
    int dp[71][1<<19];
    bool check(int x){
        for(int i=2;i*i<=x;i++){
            if(x%i==0) return 0;
        }
        return 1;
    }
    void init(){
        for(int i=2;i<=70;i++){
            if(check(i)){
                isprime[i]=tot++;
            }
        }
        for(int i=1;i<=70;i++){
            int now=i;
            for(int j=2;j*j<=now;j++){
                if(now%j==0){
                    int tot=0;
                    while(now%j==0){
                        tot++;
                        now/=j;
                    }
                    if(tot%2){
                        msk[i]|=(1<<isprime[j]);
                    }
                }
            }
            if(now!=1){
                msk[i]|=(1<<isprime[now]);
            }
        }
    }
    signed main(){
        init();
        scanf("%d",&n);
        pw[0]=1;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            pw[i]=pw[i-1]*2%mod;
            cnt[a[i]]++;
        }
        dp[0][0]=1;
        for(int i=1;i<=70;i++){
            for(int j=0;j<(1<<tot);j++){
                if(cnt[i]==0){
                    dp[i][j]+=dp[i-1][j];
                }else{
                    dp[i][j]+=dp[i-1][j]*pw[cnt[i]-1]%mod;
                    dp[i][j]+=dp[i-1][j^msk[i]]*pw[cnt[i]-1]%mod;
                }
                dp[i][j]%=mod;
            }
        }
        printf("%d\n",(dp[70][0]-1+mod)%mod);
        return 0;
    }
    
    
  • 相关阅读:
    码农提高工作效率 (转)
    Python快速教程 尾声
    C#基础——谈谈.NET异步编程的演变史
    [C#]動態叫用Web Service
    零极限 核心中的核心和详解
    项目经理应该把30%的时间用在编程上
    高效能程序员的七个习惯
    我们如何进行代码审查
    工作经常使用的SQL整理,实战篇(二)
    C# Socket网络编程精华篇 (转)
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/15533450.html
Copyright © 2011-2022 走看看