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\n",f[n][m]);
48     }
49     return 0;
50 }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章