1. 程式人生 > >【Codeforces 949D】Shake It! 【動態規劃】

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

href 動態 ++ dot ref ima scanf ces c++

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

技術分享

所求的是滿足條件的圖中“不同構”的數量,意味著操作的順序是可以忽略的。考慮若幹次操作後得到的一個“World” G,其中某次操作(s(G), t(G))生成的節點為w,則由s(G)到w和由w到t(G)的所有路徑及途徑點生成的兩個子圖分別符合“World”的定義。

這意味著我們可以將一個“World”分割成若幹個子問題來求解。

不妨令F(N, M)表示經N次操作後得到的s(G)與t(G)之間最小割為M的所有不同構的G的數量。考慮N次操作中所有基於u=s(G), v=t(G)的操作生成的子“world”,如圖所示:

技術分享

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

由此可以按照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的答案。

考慮當前要將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} $

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

代碼實現如下

技術分享
 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 }
動態規劃

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