【LOJ3600】「PA 2021」Od deski do deski(DP)
阿新 • • 發佈:2022-04-21
- 求有多少個長度為 \(n\) 、值域為 \(1\sim m\) 的序列,滿足可以通過若干次刪除長度大於 \(1\) 且兩端元素相同的區間將其刪空。
- \(1\le n\le3\times10^3\),\(1\le m\le10^9\)
判斷合法的條件
考慮如何判斷一個序列是否合法。
從左往右掃一遍,維護所有合法的端點值,初始只有第一個數的值。
如果一個位置填了合法的值,則後一個位置的值在填寫後也將變成合法的。
只要滿足最後一個數填寫時是合法的值即可。
動態規劃
發現合法的值具體是誰並沒有影響,因此只需記錄合法的值的個數。
設 \(f_{i,j}\) 表示填到第 \(i\) 個數一共有 \(j\)
轉移比較簡單,填了合法值會轉移到 \(g\),填了不合法值會轉移到 \(f\),且從 \(g\) 轉移到 \(f\) 時合法值個數會加 \(1\)。
程式碼:\(O(n^2)\)
#include<bits/stdc++.h> #define Tp template<typename Ty> #define Ts template<typename Ty,typename... Ar> #define Rg register #define RI Rg int #define Cn const #define CI Cn int& #define I inline #define W while #define N 3000 #define X 1000000007 using namespace std; int n,m,f[N+5][N+5],g[N+5][N+5]; int main() { RI i,j;for(scanf("%d%d",&n,&m),f[1][1]=m,i=2;i<=n;++i) for(j=1;j<=min(i,m);++j) f[i][j]=(1LL*f[i-1][j]*(m-j)+1LL*g[i-1][j-1]*(m-j+1))%X,g[i][j]=1LL*(f[i-1][j]+g[i-1][j])*j%X;//DP轉移 RI t=0;for(j=1;j<=min(n,m);++j) t=(t+g[n][j])%X;return printf("%d\n",t),0; }