DP搬運工2
阿新 • • 發佈:2020-08-21
DP搬運工2
題目描述
給你 \(n,K\),求有多少個 \(1\) 到 \(n\) 的排列,恰好有 \(K\) 個數 \(i(1<i<n)\) 滿足 \(a_{i-1},a_{i+1}\) 都小於 \(a_i\) 。
輸入格式
一行兩個整數 \(n,K\)。
輸出格式
一行一個整數 \(ans\) 表示答案 \(mod\ 998244353\) 。
樣例
樣例輸入1
4 1
樣例輸出1
16
樣例輸入2
10 3
樣例輸出2
1841152
資料範圍與提示
對於 \(25\%\) 的測試點,\(1\leqslant n,K \leqslant 10\) ;
對於 \(50\%\)
對於 \(100\%\) 的測試點,\(1\leqslant n,K \leqslant 2000\) ;
保證資料有梯度
分析
同樣的預設型 \(dp\) ,但是要簡單一些。我們這次只需要考慮有幾個符合條件即可。所以我們定義 \(f[i][j]\) 為插入 \(i\) 的時候,有 \(j\) 個滿足要求的數。我們仍然按照插入位置分情況。
轉移肯定是從 \(f[i-1][j]\) 轉移來,那麼我們考慮一下,什麼情況下加一個數但是符合要求的數量不變:
- 1、放到之前符合要求的某一組裡,多了一組少了一組,相當於沒變化。
- 2、放到兩個端點的時候不變。
其他情況都是不加的。然後愉快的轉移
程式碼
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int maxn = 2e3+10; const int mod = 998244353; int n,k; int f[maxn][maxn]; int main(){ scanf("%d%d",&n,&k); //初始化 f[1][0] = 1; f[2][0] = 2; for(int i=3;i<=n;++i){ int jl = min(k,i>>1);//最多有i除以2的滿足的情況。 for(int j=0;j<=jl;++j){//列舉所有的位置 if(f[i-1][j] == 0)continue; f[i][j] = (f[i][j] + f[i-1][j] * 1LL * ((j+1) << 1))%mod;//放到之前的某個裡或者邊界,此時滿足條件的不加 f[i][j+1] = (f[i][j+1] + f[i-1][j] * 1LL * (i-((j+1) << 1)))%mod;//放到其他地方,滿足條件的加一 } } printf("%d\n",f[n][k]); return 0; }