[离散化][状态压缩][集合][数论][图论][容斥原理]二分图计数

题目描述

这里写图片描述
这里写图片描述

分析

很明显是要求二分图的完备匹配数
但是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);
}

猜你喜欢

转载自blog.csdn.net/ssl_qyh0ice/article/details/80948282