某人在玩一个非常神奇的游戏。这个游戏中有一个左右各 nnn 个点的二分图,图中的边会按照一定的规律随机出现。
为了描述这些规律,某人将这些边分到若干个组中。每条边或者不属于任何组 (这样的边一定不会出现),或者只属于一个组。
有且仅有以下三类边的分组:
-
这类组每组只有一条边,该条边恰好有 50%50\%50% 的概率出现。
-
这类组每组恰好有两条边,这两条边有 50%50\%50% 的概率同时出现,有 50%50\%50% 的概率同时不出现。
- 这类组每组恰好有两条边,这两条边恰好出现一条,各有 50%50\%50% 的概率出现。
组和组之间边的出现都是完全独立的。
某人现在知道了边的分组和组的种类,想要知道完美匹配数量的期望是多少。你能帮助她解决这个问题吗?
把两条边一组的暂时看作两条边分别有1/2概率出现,这导致两条边同时出现在匹配中时的计算有误差,可以将误差用 一组两条边有±1/4概率同时出现 抵消,然后记忆化搜索,f[S]表示S集合内的点的完美匹配的期望方案数,为了保证选边的有序性并同时减少状态数,f[S]由f[S1]转移过来时,要求S最高位比S1的最高位高
#include<bits/stdc++.h> typedef long long i64; const int M=(1<<21)-1,P=1e9+7,I2=(P+1)/2,I4=I2/2; int n,m,ep=0,_; int h[M+111][2],rnd[1111]; int ht=0; int&get(int x){ _=1; int w=(x&M)^rnd[x>>21]; while(h[w][0]){ if(h[w][0]==x)return h[w][1]; w=w+1237&M; } _=0; h[w][0]=x; return h[w][1]; } struct edge{ int S,p,c; void upd(int&f,int S0,int c0){ int F(int,int); if((S0&S)==S&&S0<(S<<1)){ f=(f+F(S0^S,c0-c)*i64(p)%P)%P; } } }e[607]; int F(int S,int c){ if(!S)return 1; int&f=get(S); if(!_)for(int i=0;i<ep;++i)e[i].upd(f,S,c); return f; } int main(){ scanf("%d%d",&n,&m); srand(n+m+112); for(int i=0;i<1024;++i)rnd[i]=(rand()^rand()<<11)&M; for(int i=0,tp,a,b,c,d;i<m;++i){ scanf("%d",&tp); scanf("%d%d",&a,&b); int e1=1<<a-1|1<<n+b-1; e[ep++]=(edge){e1,I2,1}; if(tp){ scanf("%d%d",&c,&d); int e2=1<<c-1|1<<n+d-1; e[ep++]=(edge){e2,I2,1}; if(!(e1&e2))e[ep++]=(edge){e1|e2,tp==1?I4:-I4,2}; } } int ans=(i64((F((1<<n*2)-1,n)+P)%P)<<n)%P; printf("%d\n",ans); return 0; }