---
# System prepended metadata

title: Codeforces 1763D Valid Bitonic
tags: [dp]

---

# 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`


