【題解】牛客OI周賽1-提高組 C.序列 計數類DP+前綴和優化

鏈接:https://www.nowcoder.com/acm/contest/199/C
來源:牛客網
在這裏插入圖片描述
在這裏插入圖片描述


我們枚舉不同數字的個數 xx 。此時等價於這個問題,有 x 個箱子排成一排,任
意兩個箱子之間距離不超過 k(超過 k 意味着可以把這個間距減小到 k,且是一個等價的序
列),第一個箱子和最後一個箱子的距離不超過 m 的方案數。設 F[i,j]F[i,j] 表示放置了 ii 個箱子,第 11 個箱子和最後一個箱子的距離爲 jj 的方案數。
F[i,j]=l=1j1F[i1,l]F[i,j]=\sum_{l=1}^{j-1}F[i-1,l]
注意要減去超過 kk 的那些方案數。觀察到這個狀態轉移方程可以利用前綴和優化至 O(n2)O(n^2)
nn 個位置放入 xx 種不同數字一共有 S[n,k]S[n,k] 種不同的方法,其中 SS 代表第二類斯特林數。
然後還要對 xx 個數字進行大小定位,共有 x!x! 種不同方法。
目標:
i=1nj=0mS[n,i]i!f[i,j]\sum_{i=1}^n\sum_{j=0}^mS[n,i]*i!*f[i,j]

#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求解,很巧妙。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章