• 【2016NOIP十连测】【test4】【状压DP】【容斥原理】巨神兵


    题目大意:

      给一个n个点(n<=17),m条边的有向图(无自环、无重边),求其无环子图的方案数。

    题解:

      看到n<=17,显然是用状压dp。

      用f[i]表示点集i的满足条件的方案数。

      状态转移时可以一层一层地把点加进点集。

      具体的,枚举已知点集i,在i的补集中枚举下一层的点集j(可以无边相连)(以下i,j定义相同),

      统计由i连向j的边e。对于这些边,每一条都可以选或不选,

      就有2e种情况,即:

        f[i^j]+=f[i]*2e;

      这显然是错误的,

      因为对于点集k的一种连边方案,可以有多种方式划分成i,j,

      这就意味着不同的i,j可能包含了同样的方案。

      于是以j中包含的元素把并集为k的i和j分类

      转移的时候多乘个容斥系数就可以了,即:

        f[i^j]+=f[i]*2e*(-1)size(j)+1;

      复杂度O(3nm)可优化成O(3n+2nm);

    #include<cstdio>
    #include<iostream>
    using namespace std;
    typedef long long ll;
    const int N = 17;
    const int M = 300;
    const int P = 1e9+7;
    
    ll read(){
        ll re=0;bool neg=0;char ch=getchar();
        while (!isdigit(ch)) {if (ch=='-') neg=1;ch=getchar();}
        while (isdigit(ch)) re=re*10+ch-'0',ch=getchar();
        if (neg) re=-re; return re;
    }
    
    int n,m,U;
    int p2[M],coe[1<<N],g[N][N];
    int f[1<<N],deg[1<<N],sum[1<<N];
    
    void readin(){
        n=read(),m=read();
        for (int i=0;i<m;i++)
            g[read()-1][read()-1]=1;
        U=(1<<n)-1;
    }
    
    void prework(){
        p2[0]=1;coe[0]=-1;
        for (int i=1;i<=m;i++){
            p2[i]=p2[i-1]<<1;
            if (p2[i]>=P) p2[i]%=P;
        }
        for (int i=1;i<(1<<n);i++){
            coe[i]=coe[i>>1];
            if (i&1) coe[i]*=-1;
        }
    }
    
    void dp(){
        f[0]=1;
        for (int i=0;i<U;i++){
            for (int j=0;j<n;j++)deg[1<<j]=0;
            for (int j=0;j<n;j++)if ((1<<j)&i)
                for (int k=0;k<n;k++) deg[1<<k]+=g[j][k];
            int C=U^i;sum[0]=0;
            for (int tmp=(C-1)&C;;tmp=(tmp-1)&C){
                int Now=C^tmp;
                sum[Now]=sum[Now-(Now&-Now)]+deg[Now&-Now];
                f[i^Now]=(f[i^Now]+(ll)f[i]*p2[sum[Now]]*coe[Now])%P;
                if (!tmp) break;
            }
        }
    }
    
    int main(){
        readin();
        prework();
        dp();
        printf("%d
    ",f[U]);
        return 0;
    }
    View Code
  • 相关阅读:
    Rotate List
    Spiral Matrix II
    Jump Game
    Maximum Subarray
    Pow(x, n)
    Anagrams
    Permutations
    unity 相机的问题
    NGUI 学习
    空间数据库1
  • 原文地址:https://www.cnblogs.com/KaNNeXFF/p/5942983.html
Copyright © 2020-2023  润新知