1. 程式人生 > >bzoj 4321 queue2 - 動態規劃

bzoj 4321 queue2 - 動態規劃

數據 include win32 兩種 nbsp typename 由於 插入 位置

n 個沙茶,被編號 1~n。排完隊之後,每個沙茶希望,自己的相鄰的兩 人只要無一個人的編號和自己的編號相差為 1(+1 或-1)就行; 現在想知道,存在多少方案滿足沙茶們如此不苛刻的條件。

Input

只有一行且為用空格隔開的一個正整數 N,其中 100%的數據滿足 1≤N ≤ 1000;

Output

一個非負整數,表示方案數對 7777777 取模。

Sample Input

4

Sample Output

2 
樣例解釋:有兩種方案 2 4 1 3 和 3 1 4 2

  題目大意 問n個數的排列且滿足任意兩個相鄰的數的差都大於1的個數。

  顯然dp。(難道還能爆搜?)

  現在來設計狀態和轉移。因為狀態和轉移都不好想,所以根據常用套路猜測一下。

  1)f[i][j]表示已經確定了前i個數,最後一個數是j的合法方案數。看似很棒,然而你知道可行字符集嗎?當然不知道。那它能存下來嗎?當然不能(要是能存下來,和爆搜有區別嗎?)因此,只能另外思考。

  2)f[i]表示n個位置中已經填完1 - i這幾個數。然而發現。。轉移的話同樣需要很多東西。。果斷放棄

  3)考慮將排列當成一個動態數組,f[i]表示當n = i時的答案。

   考慮轉移。然而總感覺少了些什麽。。腫麽辦?加狀態!

   於是便有了f[i][j]表示已經填了1 ~ i,其中包含j個不滿足條件的對子。

   似乎轉移輕松了些。然而很快又發現了不對勁。考慮將(i + 1)插入排列,例如當i = 3時,排列 1 3 2變成排列 1 4 3 2 和排列 1 3 4 2 的時候增加的不滿足條件的對子有點不一樣,情況也不同於排列 3 1 2 將4加在3兩端。

   所以根據觀察可以得出應該增加的狀態應該是i是否和(i - 1)相鄰。

   現在開始討論幾種情況。(下面討論的轉移請自行取模)

//假設讀者的小學數學沒有問題

    i.對於f[i][j][0]的轉移

      a.首先是將(i + 1)放在i的兩端,這樣會導致增加1個不合法的對子。故有這麽一個轉移: f[i + 1][j + 1

][1] += f[i][j][0] * 2

      b.然後是將(i + 1)放在其他地方(這樣的一個地方有(i + 1 - j - 2)個,即(i - j - 1)個),使得這樣什麽都不會發生。所以就有這麽一個轉移: f[i + 1][j][0] += f[i][j][0] * 1LL * (i - j - 1)

      c.最後是將(i + 1)拿去破壞已經有的對子的相對穩定結構(我應該是化學學多了),比如在 2 3 中強行插入一個4,這樣就有個轉移: f[i + 1][j - 1][0] += f[i][j][0] * 1LL * j

    ii.對於f[i][j][1]的轉移

      a.首先是將(i + 1)放在i和(i - 1)的兩端,這樣會增加對子i和(i + 1),並且會減少1個對子,故有轉移 f[i + 1][j][1] += f[i][j][1]

      b.考慮將(i + 1)扔在上一種情況提到的一側的另一側,這樣只會增加一個對子,故有轉移 f[i + 1][j + 1][1] += f[i][j][1]

      c.然後考慮將(i + 1)放在不會有影響的地方,這樣的地方會有(i + 1 - j - 1)個,即(i - j)個,相信有人一定很好奇為什麽情況i.b是(i - j - 1),因為這個地方的j中包含了i的一端,而上面並沒有包含(如果一臉霧水請畫圖吧,個人認為比較顯然)。所以有轉移 f[i + 1][j][0] += f[i][j][1] * 1LL * (i - j)

      d.最後仍然是把(i + 1)拿去搞事情。。由於只能拆散對子,所以不能與i相鄰,所以只能有(j - 1)個位置可選擇。因此有轉移 f[i + 1][j - 1][0] += f[i][j][1] * 1ll * (j - 1)

  然後整理成程序就好了。

//Q:題目中的"沙茶"是什麽鬼
//A:當你對你的父母師長大聲說出這個詞之後你就會有深刻影響了!

Code

 1 /**
 2  * bzoj
 3  * Problem#4321
 4  * Accepted
 5  * Time: 272ms
 6  * Memory: 9132k
 7  */
 8 #include <bits/stdc++.h>
 9 using namespace std;
10 #ifdef WIN32
11 #define Auto "%I64d"
12 #else
13 #define Auto "%lld"
14 #endif
15 #define ll long long
16 
17 const int N = 1002, M = 7777777;
18 
19 int n;
20 int f[N][N][2];
21 
22 template<typename T>
23 inline void mod_plus(int& a, T b) {
24     a = (a + b) % M;
25 }
26 
27 inline void init() {
28     scanf("%d", &n);
29 }
30 
31 inline void solve() {
32     f[1][0][0] = 1;
33     for(int i = 1; i < n; i++) {
34         for(int j = 0; j < i; j++) {
35             mod_plus(f[i + 1][j + 1][1], f[i][j][0] * 2 + f[i][j][1]);
36             mod_plus(f[i + 1][j][1], f[i][j][1]);
37             mod_plus(f[i + 1][j][0], f[i][j][0] * 1LL * (i - j - 1) + f[i][j][1] * 1LL * (i - j));
38             if(j)    mod_plus(f[i + 1][j - 1][0], f[i][j][1] * 1ll * (j - 1) + f[i][j][0] * 1LL * j);
39         }
40     } 
41     printf(Auto, f[n][0][0]);
42 }
43 
44 int main() {
45     init();
46     solve();
47     return 0;
48 }

bzoj 4321 queue2 - 動態規劃