水題大戰Vol.3 B. DP搬運工2
阿新 • • 發佈:2020-08-13
水題大戰Vol.3 B. DP搬運工2
題目描述
給你\(n,K\),求有多少個\(1\)到\(n\) 的排列,恰好有\(K\)個數\(i\) 滿足\(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 \leq n,K \leq 10\);
對於 \(50\%\) 的測試點,\(1 \leq n,K \leq 100\)
對於 \(100\%\) 的測試點,\(1 \leq n,K \leq 2000\);
保證資料有梯度
分析
一道典型的計數\(DP\)題
我們設 \(f[i][j]\) 為考慮完 \(1 - i\) ,有 \(j\) 個位置滿足要求的方案數
對於 \(f[i-1][j]\) 如果我們向序列中插入一個數 \(i\) 那麼會有兩種情況
1、新插入的\(i\)插入到原來滿足要求的\(j\)個位置旁邊或者數列的兩端,此時滿足要求的位置仍然是\(j\)個,方案數為\((j+1)\times 2\)
2、\(i\)插入到原數列的其它位置,此時滿足要求的位置變為 \(j+1\) 個,方案數為 \(i-(j+1) \times 2\)
程式碼
#include<bits/stdc++.h> using namespace std; #define int long long #define mian main const int maxn=2e3+5; const int mod=998244353; int n,k,f[maxn][maxn]; signed mian(){ scanf("%lld%lld",&n,&k); f[1][0]=1,f[2][0]=2; for(int i=3;i<=n;i++){ int m=min(k,i/2); for(int j=0;j<=m;j++){ if(f[i-1][j]==0) continue; int now=f[i-1][j]; int fa=(j+1)*2; f[i][j]=(f[i][j]+f[i-1][j]*fa)%mod; f[i][j+1]=(f[i][j+1]+f[i-1][j]*(i-fa))%mod; } } printf("%lld\n",f[n][k]); return 0; }