题目描述
分析
很明显是要求二分图的完备匹配数
但是n个点都与m-1个点相连,很难运用这个条件求出,但是可以想相反条件,即容斥原理
那么容易得出:
F(S)=Σ(-1)^|S|*h(S1,S)
S1⊆S
h(S1,S)表示S1与和自己无法匹配的点匹配,S任意匹配。
都很容易求,S1只有一种匹配方案,S只用乘上另一边有多少个点即可
然后重复计算问题思考一下,(-1)^|S|就是解决这个的
#include <iostream>
#include <cstdio>
#include <algorithm>
#define rep(i,a,b) for (i=a;i<=b;i++)
const long long q=1e9+7;
using namespace std;
int n,m;
int a[17],b[17],c[17],s1[17];
long long h[17][17],f[65537];
int lcnt,s1cnt;
long long ans;
void Dfs(int d,int S,int S1) {
if (d==n) {
int t=s1cnt%2?-1:1;
f[S]=(f[S]+(long long)t*h[s1cnt][lcnt]%q)%q;
return;
}
Dfs(d+1,S,S1);
int x=1<<c[d];
if (!(S1&x)) {
s1[++s1cnt]=d;
Dfs(d+1,S+(1<<d),S1+x);
--s1cnt;
}
lcnt++;
Dfs(d+1,S+(1<<d),S1);
lcnt--;
}
int main() {
freopen("bipartite.in","r",stdin);
freopen("bipartite.out","w",stdout);
int i,j;
scanf("%d%d",&n,&m);
rep(i,0,n-1) scanf("%d",&a[i]),b[i]=a[i];
sort(b,b+n);
int sz=unique(b,b+n)-b-1;
rep(i,0,n-1)
rep(j,0,sz)
if (a[i]==b[j]) {
c[i]=j;
break;
}
rep(i,0,n) {
h[i][0]=1;
int left=m-i;
rep(j,1,n) h[i][j]=(long long)h[i][j-1]*left--%q;
}
Dfs(0,0,0);
rep(i,1,(1<<n)-1)
ans=(ans+(long long)f[i]*i%q)%q;
printf("%lld",(ans+q)%q);
}