版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/82959283
题意:
在N个格子之间,放入D-1个隔板(可以重合),要求每两个相邻隔板之间距离不超过M。求方案数。
分析:
尽管D的范围非常大,但其实很多隔板之间的距离都为0,所以可以考虑距离不为0的隔板的放置方案(即不能重合的方案)。再利用组合数求出在所有隔板中选择一定数量的方案数。
所以可以设
表示用i个格子,放置j各隔板,每两个之间距离不超过M的方案数。
这可以利用滑窗优化在
范围内算出来。
然后组合数可以直接暴力求,复杂度也是 的。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 2010
#define MOD 998244353
using namespace std;
typedef long long ll;
ll dp[MAXN][MAXN];
ll fac[MAXN],ifac[MAXN];
int t;
ll n,m,d;
ll fsp(ll x,ll y){
ll res=1;
while(y){
if(y&1ll)
res=res*x%MOD;
x=x*x%MOD;
y>>=1ll;
}
return res;
}
ll C(ll x,ll y){
ll sum=1;
for(ll i=x;i>x-y;i--){
ll i1=i%MOD;
sum=sum*i1%MOD;
}
sum=sum*ifac[y]%MOD;
return sum;
}
int main(){
fac[0]=1;
for(ll i=1;i<=2000;i++)
fac[i]=fac[i-1]*i%MOD;
ifac[2000]=fsp(fac[2000],MOD-2);
for(ll i=2000;i>=1;i--)
ifac[i-1]=ifac[i]*i%MOD;
while(SF("%lld%lld%lld",&n,&d,&m)!=EOF){
if(n==0&&d==0&&m==0)
break;
m--;
if(m==0){
PF("%d\n",(n==0));
continue;
}
memset(dp,0,sizeof dp);
dp[0][0]=1;
for(int i=1;i<=n;i++){
ll sum=dp[i-1][0];
for(int j=1;j<=n;j++){
dp[i][j]=sum;
sum=(sum+dp[i-1][j])%MOD;
if(j-m>=0)
sum=(sum-dp[i-1][j-m]+MOD)%MOD;
}
}
ll ans=0;
for(int i=1;i<=n;i++)
ans=(ans+C(d,i)*dp[i][n]%MOD)%MOD;
PF("%lld\n",ans);
}
}