HDU 5729 Rigid Frameworks

Link
给每行和每列建一个点,在一个格子里面加固就在这个格子对应的行和列连边,那么这个网格图是刚体当且仅当所有点连通。
因此我们将题目转化为了连通二分图计数。
\(f_{i,j}\) 表示\(|X|=i,|Y|=j\)的连通二分图个数,考虑补集容斥,然后枚举\(1\)号点所在连通块的左右部分的点数
\(f_{n,m}=3^{nm}-\sum\limits_{i=1}^{n}\sum\limits_{j=0}^{m}[i\ne n\vee j\neq m] \binom{n-1}{i-1}\binom{m}{j}\cdot 3^{(n-i)(m-j)}f_{i,j}\)

#include<cstdio>
const int N=11,P=1000000007;
int mod(int x){return x+(x>>31&P);}
int inc(int a,int b){return mod(a+b-P);}
int dec(int a,int b){return mod(a-b);}
int C[N][N],pw[N*N],f[N][N];
int main()
{
    pw[0]=1,f[0][1]=f[1][0]=1;
    for(int i=0,j;i<=10;++i) for(j=C[i][0]=1;j<=i;++j) C[i][j]=inc(C[i-1][j],C[i-1][j-1]);
    for(int i=1;i<=100;++i) pw[i]=3ll*pw[i-1]%P;
    for(int n=1;n<=10;++n)
    for(int m=1;m<=10;++m)
    {
        f[n][m]=pw[n*m];
        for(int i=1;i<=n;++i) for (int j=0;j<=m;++j) if (i^n||j^m) f[n][m]=dec(f[n][m],1ll*C[n-1][i-1]*C[m][j]%P*pw[(n-i)*(m-j)]%P*f[i][j]%P);
    }
    for(int n,m;~scanf("%d%d",&n,&m);) printf("%d\n",f[n][m]);
}

猜你喜欢

转载自www.cnblogs.com/cjoierShiina-Mashiro/p/12239928.html