# Codeforces 1763D Valid Bitonic > https://codeforces.com/contest/1763/problem/D 題意為給$[1,n]$序列$B$,問說總共有幾個bitonic序列使得$B_i = x$且$B_j = y$,題目表示bitonic序列為單峰序列且最高點在$[2, n-1]$之間。有$t$組數據,$1 \le t \le 100$,$1 \le n \le 100$。 不失一般性假設$i \lt j$且$x \lt y$,如果$x \gt y$的話變換一下就好($swap(x, y),\ i=n-j+1,\ j=n-i+1$),直接組合?超難==,可以看解答: > https://codeforces.com/blog/entry/110278 這題可以用DP想==,難死我了==,筆記一下。 如果我們考慮從$1$開始放進序列裡的話,一定只能從左右邊照順序放,那我們可以定義$dp(a, b, c)$為長度為$n$的空序列中,放入了$1$到$a$,且左邊放了$b$個,右邊放了$c$個的方法數, 如果沒有限制的話,因為$b+c=a$和$dp(0,0,0)=1$直接嚕上去複雜度$O(n^2)$,轉移就$dp(a, b, c) = dp(a-1, b-1, c) + dp(a-1, b, c-1)$。 如果放到$x$了,根據限制他只能放在位置$i$上,故轉移為$dp(x, i, c) = dp(x-1, i-1, c)$,沒其他可能。 再來如果放到$y$了,那麼$y$可以在左邊也可以在右邊,注意一下$y$的位置為$j$: (1) $y$在左邊$dp(y, j, c) = dp(y-1, j-1, c)$, (2) $y$在右邊$dp(y, b, n-j+1) = dp(y-1, b, n-j)$。 然後還要注意的是如果放到$n$了,$n$一定不能在最左和最右。 最後答案就是$\sum_{l=1}^{n-1} dp(n, l, n-l)$,但是這樣算的話是會重複的,放$n$時可以在左邊或右邊,所以除以二就好。 ```cpp= #include <bits/stdc++.h> #pragma GCC optimize(3) #define ll long long #define pii pair<int, int> #define pll pair<long long, long long> #define F first #define S second #define endl '\n' using namespace std; const int inf = 0x3f3f3f3f; const ll Inf = 1e18; const int mod = 1e9 + 7; const int N = 2e5 + 5; const int maxn = 5; ll inv[maxn]; void init(){ inv[0] = inv[1] = 1; for(int i=2; i<maxn; i++){ inv[i] = mod - mod/i * inv[mod%i] % mod; } return; } // dp(i, j, k) : 放1到i,左邊放j個,右邊放k個 ll dp[101][101][101]; void solve(){ int n, i, j, x, y; cin >> n >> i >> j >> x >> y; if(i >= j){ swap(i, j); swap(x, y); } if(x >= y){ i = n - i + 1; j = n - j + 1; swap(i, j); swap(x, y); } if(y == n && j == n){ cout << 0 << endl; return; } memset(dp, 0, sizeof dp); dp[0][0][0] = 1; for(int a=1; a<=n; a++){ for(int b=0; b<=a; b++){ if(a == x && b != i) continue; int c = a - b; if(a == y && b != j && c != n - j + 1) continue; if(a == n && (b == 1 || c == 1)){ if(b == 1) dp[a][b][c] = dp[a-1][b][c-1]; if(c == 1) dp[a][b][c] = dp[a-1][b-1][c]; continue; } if(a == x){ dp[a][b][c] = dp[a-1][b-1][c]; } else if(a == y){ if(b == j) dp[a][b][c] = dp[a-1][b-1][c]; if(c == n - j + 1) dp[a][b][c] = dp[a-1][b][c-1]; } else{ dp[a][b][c] += dp[a-1][b][c-1] + dp[a-1][b-1][c]; dp[a][b][c] %= mod; } } } ll ans = 0; for(int i=1; i<=n-1; i++) ans = (ans + dp[n][i][n-i]) % mod; ans = ans * inv[2] % mod; cout << ans << endl; } int main(){ ios::sync_with_stdio(0); cin.tie(0); // freopen("input.txt", "r", stdin); // freopen("output.txt", "w", stdout); init(); int t = 1; cin >> t; while(t--) solve(); return 0; } ``` ### 時間複雜度 :$O(tn^2)$ ###### tags: `dp`