zoukankan      html  css  js  c++  java
  • UOJ37 [清华集训2014] 主旋律

    (f(S)) 为点集 (S) 中强连通生成子图的方案数,(cnt(S)) 为点集 (S) 构成的诱导子图中边的个数。考虑用 (2^{cnt(S)}) 减去不合法方案数来计算 (f(S)),不合法情况即为缩点后为 (DAG)

    (h(S)) 为点集 (S) 缩点后构成点数 (>1)(DAG) 的方案数。考虑枚举一个点集 (T),其由若干个出度为 (0) 的强连通分量构成,那么点集 (S-T) 内部的边和连到 (T) 的边可以任意选取。但这样会算重,如果存在两个出度为 (0) 的强连通分量 (x,y)(T=x) 时和 (T=y) 时都会算一遍,也就是合并后点集 (S-T) 中也可能有出度为 (0) 的强连通分量。因此还需进行容斥,得:

    [large h(S)=sum_{T subseteq S,T e varnothing} (-1)^{size(T)-1}2^{e(S-T,T)}h(S-T) ]

    其中 (size(T)) 为点集 (T) 中强连通分量个数,(e(S-T,T)) 为点集 (S-T) 到点集 (T) 的边数。

    因为需要枚举强连通分量,所以复杂度无法接受。考虑将容斥系数放到 (DP) 状态中,设 (g(S)) 为点集 (S) 构成奇数个强连通分量的方案数减去构成偶数个强连通分量的方案数。转移就是枚举点集 (T),其为单独的一个强连通分量,为避免算重,还需确定一个点 (x),让 (T) 一直包含 (x),得:

    [largeegin{aligned} g(S)&=f(S)-sum_{T subset S,x in T} f(T)g(S-T) \ h(S)&=sum_{T subseteq S,T e varnothing} 2^{cnt(S)-e(T,S)}g(T)\ f(S)&=2^{cnt(S)}-h(S) end{aligned} ]

    在转移第 (f(S)) 时,要注意还不能把 (f(S)) 的贡献给 (g(S)) 算进去。

    复杂度为 (O(3^n))

    #include<bits/stdc++.h>
    #define maxn 35010
    #define p 1000000007
    #define lowbit(x) (x&(-x))
    using namespace std;
    typedef long long ll;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,m,all;
    ll pw[maxn],siz[maxn],cnt[maxn],e[maxn],f[maxn],g[maxn],in[maxn],out[maxn];
    void dfs(int s,int t)
    {
        if(s&(t-1)) dfs(s,s&(t-1));
        e[t]=e[t-lowbit(t)]+siz[in[lowbit(t)]&s];
    }
    int main()
    {
        read(n),read(m),all=(1<<n)-1,pw[0]=1;
        for(int i=1;i<=m;++i)
        {
            int x,y;
            read(x),read(y),x--,y--;
            in[1<<y]|=(1<<x),out[1<<x]|=(1<<y);
        }
        for(int i=1;i<=m;++i) pw[i]=pw[i-1]*2%p;
        for(int s=1;s<=all;++s)
            siz[s]=siz[s-lowbit(s)]+1,cnt[s]=cnt[s-lowbit(s)]+siz[in[lowbit(s)]&s]+siz[out[lowbit(s)]&s];
        for(int s=1;s<=all;++s)
        {
            f[s]=pw[cnt[s]],dfs(s,s);
            for(int t=s-lowbit(s);t;t=((t-1)&(s-lowbit(s)))) g[s]=(g[s]-f[s^t]*g[t]%p+p)%p;
            for(int t=s;t;t=(t-1)&s) f[s]=(f[s]-pw[cnt[s]-e[t]]*g[t]%p+p)%p;
            g[s]=(g[s]+f[s])%p;
        }
        printf("%lld",f[all]);
        return 0;
    }
    
  • 相关阅读:
    Android获取IMEI码
    Android动态壁纸的制作教程
    Android编程之解决androidsupportv4打包问题
    获取文字的宽度(android)
    json 数据格式
    Android隐藏标题栏,全屏显示
    android 解析json数据格式(转)
    RelativeLayout 布局属性
    anroid 样式列表
    Windows Phone 7 淺談手勢(Gestures)運作
  • 原文地址:https://www.cnblogs.com/lhm-/p/13729294.html
Copyright © 2011-2022 走看看