• [清华集训2015 Day1]主旋律-[状压dp+容斥]


     

    Description

    Solution

    f[i]表示状态i所代表的点构成的强连通图方案数。

    g[i]表示状态i所代表的的点形成奇数个强连通图的方案数-偶数个强连通图的方案数

    g是用来容斥的。

    先用f更新g。枚举状态i的编号最小点k所在连通块大小i-j,$g[i]=-sum _{jsubset i}f[i-j]*g[j]$(此处g中不更新强连通图个数为1的。

    设点集i中有sum条边,则:

    $f[i]=2^{sum}-sum _{jsubset i}2^{sum-w[j]}*g[j]$。其中w[j]是i射向j的边数,这些边被钦定不能选。

    最后记得用f[i]更新g[i]。

    Code

     

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int mod=1e9+7;
    int n,m,x,y;
    int in[40010],out[40010];
    int num[40010],sum[40010];
    ll f[40010],g[40010],bin[40010],w[40010];
    void calw(int s,int c)
    {
        if (!c) return;
        calw(s,(c-1)&s);
        w[c]=w[c^(c&-c)]+num[in[c&-c]&s];
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        bin[0]=1;for (int i=1;i<=m;i++) bin[i]=(bin[i-1]<<1)%mod;  
        for (int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);x--;y--;
            in[bin[y]]|=bin[x];
            out[bin[x]]|=bin[y];
        }
        for (int i=1;i<bin[n];i++) for (int j=0;j<n;j++) 
        if (i&bin[j]) num[i]++;
         
        for (int i=1;i<bin[n];i++)
        {
            int lowbit=i&-i,s=i^lowbit;
            for (int j=s;j;j=s&(j-1)) g[i]=(g[i]-f[j^i]*g[j]%mod)%mod;
             
            sum[i]=sum[s]+num[in[lowbit]&s]+num[out[lowbit]&s];
            f[i]=bin[sum[i]];
            calw(i,i);
             
            for (int j=i;j;j=i&(j-1))
            {
                f[i]=(f[i]-bin[sum[i]-w[j]]*g[j]%mod+mod)%mod;
            } 
            g[i]+=f[i];if (g[i]>=mod) g[i]%=mod;
        }
        cout<<f[bin[n]-1];
         
    }
  • 相关阅读:
    iOS中的隐式动画
    CALayer 为什么选择 cg 开头 而 不选择 UI 开头
    webStorm中的混乱代码格式化
    html5中的常用的库
    地下城勇士外挂
    开发板的时间设置有效,但重启恢复
    8148
    监控行人检测 .
    Linux设备驱动程序学习之分配内存
    快熟傅里叶算法图之音频wav文件
  • 原文地址:https://www.cnblogs.com/coco-night/p/9748268.html
Copyright © 2020-2023  润新知