[THUWC2017]随机二分图

dalao的博客
以前觉得很神的题。
分拆条件即可。
状压存边真是秀到我了。

#include
#define mod 1000000007
#define maxn 16
using namespace std;

#define Siz  20000007
#define Hashmod 10000007
#define inv2 (mod+1)/2
#define inv4 (mod+1)/4
int info[Hashmod],sta[Siz],val[Siz],Prev[Siz],tot;

int n,m;

int Query(int st)
{
	for(int i=info[st%Hashmod];i;i=Prev[i])
		if(sta[i] == st)
			return val[i];
	return -1;
}

void Insert(int st,int v)
{
	++tot;
	sta[tot] = st;
	val[tot] = v;
	Prev[tot] = info[st % Hashmod];
	info[st % Hashmod] = tot;	
}

int st[maxn*maxn*2],cst[maxn*maxn*2],cnt_e;

int dfs(int nsta)
{
	int tmp = 0;
	if((tmp = Query(nsta)) != -1) return tmp;
	tmp = 0;
	for(int i=1;i<=cnt_e;i++)
		if((nsta & st[i]) == st[i] && nsta < (st[i]<<1))
			tmp = (tmp + 1ll * dfs(nsta ^ st[i]) * cst[i]%mod)%mod;
	tmp = (tmp + mod) % mod;
	Insert(nsta,tmp);
	return tmp;
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int tp,a,b,c,d;
		scanf("%d",&tp);
		scanf("%d%d",&a,&b);
		a = a-1 , b = b-1 + n;
		if(tp == 0)
		{
			st[++cnt_e] = (1<<a)|(1<<b);
			cst[cnt_e] = inv2;
		}
		else 
		{
			scanf("%d%d",&c,&d);
			c=c-1,d=d-1+n;
			
			st[++cnt_e] = (1<<a)|(1<<b);
			cst[cnt_e] = inv2;
			st[++cnt_e] = (1<<c)|(1<<d);
			cst[cnt_e] = inv2;
			if(st[cnt_e]&st[cnt_e-1]) continue;
			st[++cnt_e] = (1<<a)|(1<<b)|(1<<c)|(1<<d);
			cst[cnt_e] = tp == 1 ? inv4 : mod-inv4;
		}
	}
	
	Insert(0,1);
	printf("%lld\n",1ll*(1ll<<n)*dfs((1<<(2*n))-1)%mod);
}

你可能感兴趣的:(DP优化,枚举,图论,表达式,状压DP)