• HDU 5729 Rigid Frameworks (联通块计数问题)


    题目传送门

    通过看题解画图可以发现:

    不论怎么转,一列里的横边/一行里的竖边始终平行

    当我们加固一个格子时,会让它所在的这一行的竖边和这一列的横边保证垂直

    而我们的目标是求所有竖边和横边都保证垂直的方案数

    把一行里的所有竖边看成一个点,把一列里的所有横边看成一个点。一共$n+m$个点

    把图看成二分图,左侧$n$个点,右侧$m$个点。加固一个格子相当于在左侧的一个点和右侧的一个点之间连边!

    我们的问题变成了求解二分图的连通图个数!

    接下来就是很套路的$DP$了

    定义$f(a,b)$表示左边$a$个点,右边$b$个点的连通二分图个数

    对于连通图问题,我们依然采用常规的“固定思想”,我们固定左侧第一个点

    直接求联通很困难,考虑用不合法的情况相减,可得$DP$方程:

    $f(a,b)=3^{ab}-sum_{i=0}^{a}sum_{j=0}^{b}f(i,j)C_{a-1}^{i-1}C_{b}^{j}3^{(a-i)(b-j)}$

    (注意i=a,j=b是不能转移的)

    初值怎么赋需要思考

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define N1 65
     5 #define M1 3605
     6 #define ll long long
     7 using namespace std;
     8 const ll p=1000000007;
     9 
    10 int n,m,T;
    11 int pw3[M1],C[N1][N1],f[N1][N1];
    12 
    13 int main()
    14 {
    15     int i,j,a,b; n=60; m=60;
    16     for(i=1,pw3[0]=1;i<=n*m;i++) pw3[i]=3ll*pw3[i-1]%p;
    17     C[0][0]=1;
    18     for(i=1;i<=max(n,m);i++)
    19     {
    20         C[i][0]=C[i][i]=1;
    21         for(j=1;j<i;j++)
    22             C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;
    23     }
    24     f[1][0]=1; f[1][1]=2; //pw3[0]=0;
    25     for(a=1,b=2;b<=m;b++)
    26     {
    27         f[a][b]=pw3[a*b];
    28         for(j=0,i=1;j<b;j++)
    29         {
    30             f[a][b]=(f[a][b]-1ll*f[i][j]*C[a-1][i-1]%p*C[b][j]%p*pw3[(a-i)*(b-j)]%p+p)%p;
    31         }
    32     }
    33     for(a=2;a<=n;a++)
    34     {
    35         for(b=1;b<=m;b++)
    36         {
    37             f[a][b]=pw3[a*b];
    38             for(i=1;i<a;i++)
    39             for(j=0;j<=b;j++)
    40                 f[a][b]=(f[a][b]-1ll*f[i][j]*C[a-1][i-1]%p*C[b][j]%p*pw3[(a-i)*(b-j)]%p+p)%p;
    41             for(j=0,i=a;j<b;j++)
    42                 f[a][b]=(f[a][b]-1ll*f[i][j]*C[a-1][i-1]%p*C[b][j]%p*pw3[(a-i)*(b-j)]%p+p)%p;
    43         }
    44     }
    45     while(scanf("%d%d",&n,&m)!=EOF)
    46     {    
    47         printf("%d
    ",f[n][m]);
    48     }
    49     return 0;
    50 }
  • 相关阅读:
    忘记oracle的sys用户密码怎么修改
    C语言 给字符数组赋值的方法
    linux编译中的常见问题
    Ubuntu下查看linux版本,内核版本,系统位数,gcc版本
    Win7中打开chm文件内容无法显示问题
    exit()与_exit()函数的区别(Linux系统中)
    【BZOJ3456】城市规划(生成函数,多项式运算)
    【BZOJ3028】食物(生成函数)
    【CF438E】The Child and Binary Tree(多项式运算,生成函数)
    【BZOJ3771】Triple(生成函数,多项式运算)
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10566844.html
Copyright © 2020-2023  润新知