[THUWC2017]随机二分图
考虑 \(n\) 很小,我们可以通过记录二分图的匹配状态进行转移
主要讲一下这道题的精髓
注意到我们只关心一条边是否在完美匹配中出现
我们可以把 \(t=1\) \(t=2\) 的情况拆成 \(t=0\) 的情况
\(t=1\) :
设两条边分别为 \(a,b\) ,我们在开始时把他们当成 \(t=0\) 的状态
如果 \(a\) 单独出现在完美匹配中,那么他贡献概率为 \(\frac{1}{2}\) ,符合题意
\(b\) 同理
如果 \(a,b\) 同时出现在完美匹配中,我们计算的概率为 \(\frac{1}{4}\) ,但事实上概率为 \(\frac{1}{2}\) ,根据期望的线性性质,我们再加上同时选的概率 \(\frac{1}{4}\) ,正确性显然
\(t=2\) 的情况同理
精髓主要是在题意的转化
Code
#include <bits/stdc++.h>
#define re register
#define int long long
#define lls long long
#define pir make_pair
#define fr first
#define sc second
#define db double
using namespace std;
const int mol=1e9+7;
const int maxn=1e5+10;
const int INF=1e9+10;
inline int qpow(int a,int b) { int ans=1; while(b) { if(b&1) (ans*=a)%=mol; (a*=a)%=mol; b>>=1; } return ans; }
inline int read() {
int s=0,w=1; char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { s=s*10+ch-'0'; ch=getchar(); }
return s*w;
}
int n,m,inv2=qpow(2,mol-2),inv4=qpow(4,mol-2); unordered_map<int,int> vis[1<<20];
int tot; struct WOR { int s,t,p; } wor[maxn];
inline void ad(int & x) { x=x>=mol? x-mol:x; }
inline int dfs(int S,int T) {
if(!S) return 1;
if(vis[S][T]) return vis[S][T];
int ans=0;
for(re int i=1;i<=tot;i++) {
int s=wor[i].s,t=wor[i].t;
if((S|s)!=S||(T|t)!=T||S>=(s<<1)) continue;
ad(ans+=dfs(S^s,T^t)*wor[i].p%mol);
}
return vis[S][T]=ans;
}
signed main(void) {
n=read(); m=read();
for(re int i=1,opt,x,y,xx,yy;i<=m;i++) {
opt=read(); x=read(); y=read();
if(!opt) { wor[++tot]=(WOR){ 1<<x-1,1<<y-1,inv2 }; continue; }
xx=read(); yy=read();
int s=(1<<x-1)|(1<<xx-1),t=(1<<y-1)|(1<<yy-1);
if(opt==1) {
wor[++tot]=(WOR){ 1<<x-1,1<<y-1,inv2 };
wor[++tot]=(WOR){ 1<<xx-1,1<<yy-1,inv2 };
if(x==xx||y==yy) continue;
wor[++tot]=(WOR){ s,t,inv4 };
} else {
wor[++tot]=(WOR){ 1<<x-1,1<<y-1,inv2 };
wor[++tot]=(WOR){ 1<<xx-1,1<<yy-1,inv2 };
if(x==xx||y==yy) continue;
wor[++tot]=(WOR){ s,t,mol-inv4 };
}
}
printf("%lld\n",dfs((1<<n)-1,(1<<n)-1)*qpow(2,n)%mol);
}