gfoj A

题目:http://www.gdfzoj.com/oj/contest/475/problems/3

我们有n个相同的弹珠,k个相同的盒子.现在随机的将每个弹珠扔进盒子中,使得最终每个盒子非空,求出一共有多少种不同的方案.

两种方案不同当且仅当将盒子中的弹珠数最小表示后不同.

由于方案数可能非常多,答案对998244353取模

输入

7 3

输出

4

 

很容易想到dp,也容易想到f[i,j]:i个弹珠分j份,也容易想到跟f[i-1,j-1]有关

但是怎么推公式呢?

首先看一下题目:题目要求方案不考虑顺序,所以我们尽量把处理的k位是最小的即从小到大(防止重复)

就按样例枚举:f[7,3]=4 :1/1/5 1/2/4  1/3/3 2/2/3

对应 f[6,2]=3:1/5  2/4  3/3 

那剩下的1个怎么办?

经观察剩下的是 2/2/3 ,但你又不能+f[5,2] ,会出现重复

仔细想想,f[6,2]对应的最小值是1(保证了顺序不会重复),那么剩余的就是>=2的,但又不能出现1

那我们就把所有j份都-1,这样不就可以出现1咯

即+f[4,3]:1/1/2  >>所有+1>>2/2/3 咯

所以f[i,j]=f[i-1,j-1]+f[i-j,j]

 

 

f[7,3]例子不是特别好(考试时要自己多出些数据,样例不一定是最好的),还是不懂可以枚举f[10,3]

f[10,3]=8  : 1/1/8  1/2/7   1/3/6   1/4/5    2/2/6   2/3/5   2/4/4   3/3/4

f[9,2]=4  :  1/8  2/7  3/6  4/5

剩下的4个是   2/2/6  2/3/5  2/4/4   3/3/4 

这些的共同特点就是最小值都>=2

为了良好利用上f[i,j],把所有盒子里的弹珠都-1,最小值>=1 ,满足f[i,j]

所以剩下4=f[i-j,j]=f[7,3]  :  1/1/5 1/2/4  1/3/3 2/2/3

所以。。。

 

注意要取模!!!!!!!!!

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int maxS=5000,value=998244353;
long long f[maxS+5][maxS+5];

int main()
{
	int i,n,m,j;
	
	freopen("a.txt","r",stdin);
	scanf("%d%d",&n,&m);
	for (i=1;i<=n;i++)
		for (j=1;j<=min(i,m);j++)
		{
			if (i==j)
				f[i][j]=1;
			else
				f[i][j]=(f[i-1][j-1]+f[i-j][j])%value;
		}
	printf("%lld\n",f[n][m]);
	
	
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值