【DP】2018国庆三校联考D1T1

24 篇文章 0 订阅

题意:

在N个格子之间,放入D-1个隔板(可以重合),要求每两个相邻隔板之间距离不超过M。求方案数。
N , M ≤ 2000 N,M\leq 2000 N,M2000
D ≤ 1 0 12 D\leq 10^{12} D1012


分析:

尽管D的范围非常大,但其实很多隔板之间的距离都为0,所以可以考虑距离不为0的隔板的放置方案(即不能重合的方案)。再利用组合数求出在所有隔板中选择一定数量的方案数。

所以可以设 D P ( i , j ) DP(i,j) DP(i,j)表示用i个格子,放置j各隔板,每两个之间距离不超过M的方案数。
这可以利用滑窗优化在 O ( n 2 ) O(n^2) O(n2)范围内算出来。

然后组合数可以直接暴力求,复杂度也是 O ( n 2 ) O(n^2) O(n2)的。

#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);
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值