【Codeforces 949D】Shake It! 【動態規劃】

參考: http://blog.csdn.net/gjghfd/article/details/77824901c++

 

 

 

 

所求的是知足條件的圖中「不一樣構」的數量,意味着操做的順序是能夠忽略的。考慮若干次操做後獲得的一個「World」 G,其中某次操做(s(G), t(G))生成的節點爲w,則由s(G)到w和由w到t(G)的全部路徑及途徑點生成的兩個子圖分別符合「World」的定義。
ide

 

這意味着咱們能夠將一個「World」分割成若干個子問題來求解。spa

 

不妨令F(N, M)表示經N次操做後獲得的s(G)與t(G)之間最小割爲M的全部不一樣構的G的數量。考慮N次操做中全部基於u=s(G), v=t(G)的操做生成的子「world」,如圖所示:.net

 

則有$$N = \sum_i (a_i + c_i + 1) \\ M = \sum_i \min\{b, d\} $$code

由此能夠按照a, b, c, d對這些成對的子世界分類,令$$g(i, j) = \sum_{a+c+1=i \land min\{b, d\} = j} F(a, b) * F(c, d) $$

這樣咱們就能夠類比揹包問題的求解過程,從小到大依次求出g(i, j),並用g(i, j)更新F的答案。blog

考慮當前要將t組在g(i, j)中的「子世界對」放入揹包,而F(x,y)是還沒有考慮將g(i, j)做爲子世界的狀況的世界數量,那麼狀態轉移的過程就至關於在g(i,j)中可重複地選取t個子世界對,使得總操做數變爲x+t*i,總割集變爲y+t*j。因爲「同構」的定義不考慮操做的順序,上述轉移的方案數應爲$\binom{g(i, j) + t - 1}{t} $get

即狀態轉移爲$$F(x, y) \cdot \binom{g(i, j) + t - 1}{t} \Longrightarrow F(x+t*i, y+t*j)$$it

代碼實現以下io

 1 By Asm.Def, contest: Codeforces Round #431 (Div. 1), problem: (D) Shake It!, Accepted, #
 2 
 3 #include <bits/stdc++.h>
 4 using namespace std;
 5 const int maxn = 52, mod = 1000000007;
 6 typedef long long LL;
 7 int N, M, F[maxn][maxn], G[maxn][maxn], inv[maxn];
 8 
 9 void init()
10 {
11     scanf("%d%d", &N, &M);
12     inv[1] = 1;
13     for(int i = 2;i < maxn;++i)
14         inv[i] = LL(mod-mod/i) * inv[mod%i] % mod;
15 }
16 void work()
17 {
18     F[0][1] = 1;
19     for(int i = 1;i <= N;++i) for(int j = 1;j < maxn;++j)
20     {
21         for(int a = 0;a < i;++a)
22         {
23             G[i][j] = (G[i][j] + (LL) F[a][j] * F[i-1-a][j]) % mod;
24             for(int b = j+1;b <= i+1 && b < maxn;++b)
25             {
26                 G[i][j] = (G[i][j] + (LL) F[a][b] * F[i-1-a][j]) % mod;
27                 G[i][j] = (G[i][j] + (LL) F[a][j] * F[i-1-a][b]) % mod;
28             }
29         }
30         //get G[i][j]
31         for(int x = N-1;x >= 0;--x) for(int y = 1;y < maxn;++y) if(F[x][y])
32         {
33             int C = 1;
34             for(int t = 1;x+t*i <= N && y+t*j < maxn;++t)
35             {
36                 C = (LL) C * (G[i][j]-1+t) % mod * inv[t] % mod;
37                 F[x+t*i][y+t*j] = (F[x+t*i][y+t*j] + (LL) F[x][y] * C) % mod;
38             }
39         }
40     }
41     printf("%d\n", F[N][M]);
42 }
43 int main()
44 {
45     init();
46     work();
47     return 0;
48 }
動態規劃
相關文章
相關標籤/搜索