题解:
考试时忙着想前面两道题了,没怎么看。
看这个n的范围,估计是状压。
考虑
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j],左边匹配状态为i,右边为j时的概率。显然两边匹配点数相同。答案是
d
p
[
2
n
−
1
]
[
2
n
−
1
]
×
2
n
dp[2^n-1][2^n-1]\times{2^n}
dp[2n−1][2n−1]×2n。
当然不能直接开数组。map吼哇。
如果t=0,直接转移就行了。
如果t=1,把边拆掉,各自连接两条边,期望
1
2
\frac{1}{2}
21,再把四个点都连接起来,期望
1
4
\frac{1}{4}
41。
如果t=2,和t=1基本相同,把四个点连接起来时期望是
−
1
4
-\frac{1}{4}
−41。
因为同时出现的边组(x1,y1,x2,y2),在x1或y1已经被匹配的时候能对匹配(x2,y2)产生50%的贡献,在x2或y2已经被匹配的时候能对匹配(x1,y1)产生50%的贡献,但是对同时匹配(x1,y1),(x2,y2)只能产生25%的贡献,所以要补上25%的同时出现的贡献。
同理只出现一条的边组(x1,y1,x2,y2),在拆成(x1,y1)(x2,y2)时,对同时匹配(x1,y1)(x2,y2)时会多产生25%的贡献,所以要加上一组-25%同时出现的边组
(by:LowestJN)
至于连四个点时要特判的原因…我猜是因为如果有相交,因为一条边只会出现一次,所以两边的点就会不一样,就会导致一个不合法的结果。但是分别连的时候就不影响答案?emmm…大概是匹配到一条边之后就不会匹配到与之相交的另一条边?
这题面真是有毒QAQ出题人想表达得到了图之后匹配的个数?
代码:
#include<cstdio>
#include<map>
#define maxn 32770
#define maxm 1005
#define mod 1000000007
#define inv2 500000004
#define inv4 250000002
using namespace std;
int n,m,st[maxm],p[maxm],cnt;
map<int,int> dp[maxn];
int DP(int S)
{
if(!S) return 1;
int s=S&((1<<n)-1),t=S>>n;
if(dp[s].count(t)) return dp[s][t];
int res=0;
for(int i=1;i<=cnt;i++)
if((S&st[i])==st[i]&&S<st[i]*2) res=(res+1ll*DP(S^st[i])*p[i]%mod)%mod;
return dp[s][t]=res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int tp,a1,b1,a2,b2,x,y;
scanf("%d%d%d",&tp,&a1,&b1); a1--,b1+=n-1;
cnt++,x=st[cnt]=(1<<a1)|(1<<b1),p[cnt]=inv2;
if(tp)
{
scanf("%d%d",&a2,&b2); a2--,b2+=n-1;
cnt++,y=st[cnt]=(1<<a2)|(1<<b2),p[cnt]=inv2;
if(!(x&y)) cnt++,st[cnt]=x|y,p[cnt]=tp==1?inv4:(mod-inv4);
}
}
printf("%lld\n",(1ll<<n)*DP((1<<(n*2))-1)%mod);
}