2022杭电多校九 1007-Matryoshka Doll(动态规划)

题目链接:杭电多校九 - Virtual Judge
题目:

 样例输入:

2
4 3 2
1 2 3 4
4 2 1
1 1 2 2

样例输出:

3
2

题意:有n个套娃,大小为a1<=a2<=……<=an,现在要将这些套娃分成k组,每组套娃按照大小排序后相邻两个套娃之间的大小差距要求>=r,求方案数。

分析:设f[i][j]表示将前i个娃分成j组的合法方案数

下面说一下递推方程怎么推导

首先f[i][j]可以由i-1的两种情况转移而来,一种是前i-1个套娃分成了j-1组,第i个套娃单独成为一组的情况另一种情况是前i-1个套娃分成了j组,第i个套娃放在已经分好的j组的其中一组里面,那么问题来了,我们应该把第i个套娃放在哪一组呢?换句话说是有多少组是可以放下第i个套娃的呢?只要是该组最大值小于等于a[i]-r,那么这一组就可以放下第i个套娃,而且我们能够知道对于套娃的大小在[a[i]-r+1,a[i]]的套娃,是不可能有两个或者多个套娃分在同一组的,一定是分在不同的组里面,那么也就是说大小介于[a[i]-r+1,a[i]]的套娃有多少个,那么就会有多少组是不能放第i个套娃的,不妨假设是x个,那么就会有j-x组是可以放第i个套娃的,那么这种情况对应的情况数就是f[i-1][j]*(j-x),x直接暴力求解就行,那么总的递推方程就是f[i][j]=(f[i-1][j-1]+1ll*f[i-1][j]*max(0,j-t))%mod

初始值就是f[0][0]=1.

细节见代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=5e3+10,mod=998244353;
int f[N][N];//f[i][j]表示将前i个娃分成j组的合法方案数 
int a[N];
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n,k,r;
		scanf("%d%d%d",&n,&k,&r);
		f[0][0]=1;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			int t=i-1;//t记录有多少个j满足a[j]-a[i]<r
			while(t&&a[i]-a[t]<r) t--;
			t=i-t-1;
			for(int j=1;j<=i;j++)
				f[i][j]=(f[i-1][j-1]+1ll*f[i-1][j]*max(0,j-t))%mod;
		}
		printf("%d\n",f[n][k]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值