题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5230
解题思路:
这是一个整数划分的模型:
将n划分为k个整数的划分数
设dp[i][j]为将i划分为j个整数的划分数。
(1) i<j为不可能出现的情况,dp[i][j]=0;
(2) 若i=j,有一种情况:i可以划分为i个1之和,dp[i][j]=1;
(3) 若i>j,可以根据划分数中是否含有1分为两类:若划分数中含有1,可以使用“截边法”将j个划分分别截去一个1,把问题转化为i-j的j-1个划分数,为dp[i-j][j-1]; 若划分中不包含1,使用“截边法”将j个划分数的最下面一个数截去,将为题转化为求i-j的j个划分数,为dp[i-j][j]。所以i>j时dp[i][j]=dp[i-j][j-1]+dp[i-j][j]。
这道题是一样的,dp[i][j]表示将i划分成j个不同的数,与上面不同的是,这里当i=j时我们是不处理的,即我们不能出现i=j的情况。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 100005;
const int mod = 998244353;
int n,L,R,C,dp[2][maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d%d",&n,&C,&L,&R);
L -= C,R = min(R-C,n-1);
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
int ans = L <= 0 ? 1 : 0;
for(int i = 1; (1 + i) * i / 2 <= R; i++) //枚举人数
{
for(int j = (1 + i) * i / 2; j <= R; j++) //枚举分数
{
dp[i & 1][j] = (dp[i & 1][j - i] + dp[(i - 1) & 1][j - i]) % mod;
if(L <= j && j <= R)
ans = (ans + dp[i & 1][j]) % mod;
}
memset(dp[(i - 1) & 1],0,sizeof(dp[(i - 1) & 1]));
}
printf("%d\n",ans);
}
return 0;
}