• BZOJ3812 主旋律(状压dp+容斥原理)


      设f[S]为S点集是SCC的方案数。考虑通过去掉不合法方案转移。可以枚举入度为0的SCC所含点集S',这样显然S^S'内部的边和由S'连向S^S'的边删还是不删任选。但是这样无法保证S'包含所有入度为0的SCC,于是考虑容斥,瞎猜可以得到容斥系数与SCC数量有关,于是设g[i][S]为S包含i个无关SCC的方案数,转移有f[S]=2cnt(S)-Σ(-1)j*g[j][S']*2cnt(S^S')+cnt(S' to S^S'),g的转移通过枚举编号最小点所在SCC实现。注意到g[j][]的贡献只与j的奇偶性有关,于是可以改成g[S]为S有偶数个无关SCC的方案数,h[S]为S有奇数个无关SCC的方案数,转移类似。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 15
    #define P 1000000007
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
    	int x=0,f=1;char c=getchar();
    	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    int n,m,a[N][N],e[1<<N],s[N][1<<N],p[N*N*N],f[1<<N],g[1<<N],h[1<<N];
    int trans(int x)
    {
    	int s=-1;
    	while (x) s++,x>>=1;
    	return s;
    }
    int calc(int x,int y)
    {
    	int u=0;
    	for (int i=0;i<n;i++)
    	if (x&(1<<i)) u+=s[i][y];
    	return u;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    	const char LL[]="%I64d
    ";
    #else
    	const char LL[]="%lld
    ";
    #endif
    	n=read(),m=read();
    	for (int i=1;i<=m;i++)
    	{
    		int x=read()-1,y=read()-1;
    		a[x][y]=1;
    	}
    	for (int i=0;i<(1<<n);i++)
    		for (int x=0;x<n;x++)
    		if (i&(1<<x))
    			for (int y=0;y<n;y++)
    			if (i&(1<<y)) e[i]+=a[x][y];
    	for (int i=0;i<n;i++)
    		for (int j=1;j<(1<<n);j++)
    		s[i][j]=s[i][j^(j&-j)]+a[i][trans(j&-j)];
    	p[0]=1;for (int i=1;i<=m;i++) p[i]=(p[i-1]<<1)%P;
    	for (int i=1;i<(1<<n);i++)
    	{
    		f[i]=p[e[i]];
    		int x=0;
    		for (int j=0;j<n;j++) if (i&(1<<j)) {x=j;break;}
    		for (int j=i-1&i;j;j=j-1&i)
    		if (j&(1<<x))
    		{
    			g[i]=(g[i]+1ll*h[i^j]*f[j])%P;
    			h[i]=(h[i]+1ll*g[i^j]*f[j])%P;
    		}
    		for (int j=i;j;j=j-1&i)
    		f[i]=(f[i]+1ll*(g[j]+P-h[j])*p[e[i^j]+calc(j,i^j)]%P)%P;
    		h[i]=(h[i]+f[i])%P;
    	}
    	cout<<f[(1<<n)-1];
    	return 0;
    }
    

      

  • 相关阅读:
    java虚拟机学习-JVM调优总结-基本垃圾回收算法(7)
    学习笔记-人脸识别第三讲
    小波变换基础理论
    小波变换图像分解
    图像的纹理区域分类
    matlab中图片数据类型转换uint8与double
    八板体-器乐曲
    【歌词】金蛇狂舞-许笑薇-童声
    【歌词】金蛇狂舞-龙飘飘
    NLM算法
  • 原文地址:https://www.cnblogs.com/Gloid/p/10652612.html
Copyright © 2020-2023  润新知