THUWC2017 随机二分图

一道神仙题
题目链接


这个数据很状压啊
但是(type=2,3)的有点麻烦.
(f[S])表示集合为(S)的完美匹配期望.
一条边相当于一种转移.
我们考虑把两条边分开计数,各有(50\%)的概率出现.
假设第一条边是((u,v)),第二条边是((x,y))
如果(type=2),那么两条边都出现的概率应该是(50\%),然而我们计算的概率是(25\%),因此我们要给整个点集加入一个(25\%)的偏移量.
同理如果(type=3),那么两条边都出现的概率应该是(0),那么我们给整个点集加入一个(-25\%)的偏移量.
如果这两条边有公共点,那么我们肯定无法同时选择这两条边.那么就不用加偏移量.

然后就可以愉快地状压啦.
状压时有一个常用的小(trick)就是钦定转移最高位来减小复杂度.
哦还有一个问题.
我们存不下这个(dp)值,开个(map)就好啦

代码如下

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<bitset>
#include<set>
#define N (15)
#define P (1000000007)
#define inf (0x7f7f7f7f)
typedef long double ld;
typedef long long LL;
typedef unsigned long long ull;
using namespace std;
namespace fastIO1{
	inline char read(){
		static const int IN_LEN=1000000;
		static char buf[IN_LEN],*s,*t;
		return (s==t?t=(s=buf)+fread(buf,1,IN_LEN,stdin),(s==t?-1:*s++):*s++);
	}
	template<class T>
	inline void read(T &x){
		static bool iosig;
		static char c;
		for(iosig=false,c=read();!isdigit(c);c=read()){
			if(c=='-')iosig=true;
			if(c==-1)return;
		}
		for(x=0;isdigit(c);c=read())x=((x+(x<<2))<<1)+(c^'0');
		if(iosig)x=-x;
	}
	inline char readc(char &c){
		for(c=read();!isalpha(c)&&!isdigit(c);c=read())
		if(c==-1)return 0;
	}
	const int OUT_LEN = 10000000;
	char obuf[OUT_LEN],*ooh=obuf;
	inline void print(char c) {
		if(ooh==obuf+OUT_LEN)fwrite(obuf,1,OUT_LEN,stdout),ooh=obuf;
		*ooh++=c;
	}
	template<class T>
	inline void print(T x){
		static int buf[30],cnt;
		if(x==0)print('0');
		else{
			if(x<0)print('-'),x=-x;
			for(cnt=0;x;x/=10)buf[++cnt]=x%10+48;
			while(cnt)print((char)buf[cnt--]);
		}
	}
	inline void flush(){fwrite(obuf,1,ooh-obuf,stdout);}
}
namespace fastIO2{
	template<class T>
	inline void read(T &x){
		static bool iosig;
		static char c;
		for(iosig=false,c=getchar();!isdigit(c);c=getchar()){
			if(c=='-')iosig=true;
			if(c==-1)return;
		}
		for(x=0;isdigit(c);c=getchar())x=((x+(x<<2))<<1)+(c^'0');
		if(iosig)x=-x;
	}
}
using namespace fastIO1;
const int inv2=(P+1)>>1,inv4=(P+1)>>2;
int n,m,cnt;struct node{LL S;int p;}a[233333];
map<int,int>f[1<<16];
LL calc(int x,int y){return (1ll<<x-1)+(1ll<<(y+n-1));}
int dp(LL S){
	if(!S)return 1;
	int L=S>>n,R=S^(L<<n);
	if(f[L].count(R))return f[L][R];
	int ans=0;
	for(int i=1;i<=cnt;i++){
		LL T=a[i].S;
		if((T&S)==T&&(T<<1)>S)
		(ans+=1ll*dp(S^T)*a[i].p%P)%=P;
	}
	return f[L][R]=ans;
}
int main(){
	read(n),read(m);
	for(int i=1;i<=m;i++){
		int tp,x,y;LL S;
		read(tp),read(x),read(y),S=calc(x,y);
		a[++cnt]=(node){S,inv2};
		if(tp){
			int x1,y1,S1; read(x1),read(y1),S1=calc(x1,y1);
			a[++cnt]=(node){S1,inv2};if(S&S1)continue;
			a[++cnt]=(node){S|S1,(tp==2?-1:1)*inv4};
		}
	}
	printf("%lld
",(1ll*(1ll<<n)*dp((1ll<<(2*n))-1)%P+P)%P);
}
原文地址:https://www.cnblogs.com/Romeolong/p/10288105.html