【題解】牛客OI周賽1-提高組 C.序列 計數類DP+字首和優化
阿新 • • 發佈:2018-12-13
我們列舉不同數字的個數 。此時等價於這個問題,有 x 個箱子排成一排,任 意兩個箱子之間距離不超過 k(超過 k 意味著可以把這個間距減小到 k,且是一個等價的序 列),第一個箱子和最後一個箱子的距離不超過 m 的方案數。設 表示放置了 個箱子,第 個箱子和最後一個箱子的距離為 的方案數。 注意要減去超過 的那些方案數。觀察到這個狀態轉移方程可以利用字首和優化至 。 將 個位置放入 種不同數字一共有 種不同的方法,其中 代表第二類斯特林數。 然後還要對 個數字進行大小定位,共有 種不同方法。 目標:
#include<cstdio> #include<iostream> using namespace std; typedef long long ll; const ll mod=998244353; const int N=2e3+10; int n,m,k; ll fac[N],sum[N],f[N][N],s[N][N],ans; int main() { scanf("%d%d%d",&n,&m,&k); fac[0]=1; for(int i=1;i<=n;i++) { s[i][1]=s[i][i]=1;fac[i]=(fac[i-1]*i)%mod; for(int j=2;j<i;j++) s[i][j]=(s[i-1][j-1]+j*s[i-1][j]%mod)%mod; } f[1][0]=1; for(int i=2;i<=n;i++) { sum[0]=f[i-1][0]; for(int j=1;j<=m;j++) sum[j]=(sum[j-1]+f[i-1][j])%mod; for(int j=1;j<=m;j++) f[i][j]=sum[j-1]; for(int j=k+1;j<=m;j++) f[i][j]=(f[i][j]-sum[j-k-1]+mod)%mod; } for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) ans=(ans+(s[n][i]*fac[i]%mod)*f[i][j]%mod)%mod; printf("%lld\n",ans); return 0; }
總結
初拿到這道題毫無頭緒。這題轉化為一個放箱子的模型,通過一系列分析利用DP求解,很巧妙。