某dp题

【NOI联考by ysy】庆典

2016年6月17日1,1040

【题目描述】

战狂在昌和帝国的首都法法城召开了庆典,向一万名最杰出的士兵分发了用魔法猪做的猪肉饺子,士兵们吃了猪肉饺子后,战斗力大幅提高。
为了保护战狂的安全以及维护现场秩序,大预言家抽调了n名普通士兵组成了m个小队完成一些不同的任务。由于一些特殊的原因,所有小队的人数都互不相同。
你需要求出有多少种可能的组队方案。注意士兵是相同的,而小队是不同的。

【输入数据】

第一行两个个整数n,m。

【输出数据】

一行一个数表示答案。对998244353取模。

【样例输入】

16 4

【样例输出】

216

【数据范围】

对于20%的数据,n,m<=20。
对于50%的数据,n,m<=3000。
对于100%的数据,n,m<=100000。

这个题目就比较简单
首先所有小队的人都不相同
那就先给每个位置(i)分配(i)个队员
对于剩下的人就分配给这m个小队
所以就(O(nm))递推

这个递推有点熟悉(整数拆分问题)

递推法
根据n和m的关系,考虑下面几种情况:
(1)当n=1时,不论m的值为多少(m>0),只有一种划分,即({1})
(2)当m=1时,不论 的值为多少(n>0),只有一种划分,即({1,1,....1,1,1})
(3)当n=m时,根据划分中是否包含n,可以分为两种情况:
(a)划分中包含n的情况,只有一个,即({n})
(b)划分中不包含n的情况,这时划分中最大的数字也一定比n小,即n的所有((n-1))划分;
因此,(f(n,n)=1+f(n, n-1))
(4)当n时,由于划分中不可能出现负数,因此就相当于f(n,n);
(5)当n>m时,根据划分中是否包含m,可以分为两种情况:
(a)划分中包含 的情况,即{m,{x1,x2,x3,...,xi}},其中{x1,x2,x3,...,xi}的和为n-m,可能再次出现m,因此是(n-m)的m划分,因此这种划分个数为f(n-m,m;
(b)划分中不包含m的情况,则划分中所有值都比m小,即n的(m-1)划分,个数为f(n,m-1;
因此,f(n,m)=f(n-m,m)+f(n,m-1) 。
综合以上各种情况,可以看出,上面的结论具有递归定义的特征,其中(1)和(2)属于回归条件,(3)和(4)属于特殊情况,而情况(5)为通用情况,属于递归的方法,其本质主要是通过减少n或m以达到回归条件,从而解决问题。
详细递推公式描述如下:

那么

#include<iostream>
#include<cstdio>
#define N 100005
#define mod 998244353
using namespace std;

int dp[N];

int main(){
	int n,m;
	cin>>n>>m;
	n-=m*(m+1)/2;
	dp[0]=1;
	for(int i=1;i<=m;++i)
		for(int j=i;j<=n;++j)
			dp[j]=(dp[j]+dp[j-i])%mod;
	for(int i=2;i<=m;++i)
		dp[n]=(dp[n]*i)%mod;
	printf("%d",dp[n]);
	return 0;
}
原文地址:https://www.cnblogs.com/qdscwyy/p/7806133.html