Equation
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 492 Accepted Submission(s): 166
x1+x2+x3+⋯+xn=n, and here
For a certain n, Gorwin wants to know how many combinations of xi satisfies above condition.
For the answer may be very large, you are expected output the result after it modular m.
In the next T lines, every line contain two integer n,m.
[Technical Specification]
1≤T<20
1≤n≤50000
1≤m≤1000000000
See the samples for more details.
2 3 100 5 100
Case #1: 2 Case #2: 3
思路:首先分析该条件可以发现该序列一定不能从2或者2以上的数字开始
因为我们假设有n个数,然后序列从2开始,那么序列最少为2*n>n
所以序列只能从0或者1开始,并且去重后一定是连续的序列,这点应该比较容易看出来,后一个数要么是前一个数,要么是前一个数+1
那么我们把序列去重,最后的结果一定是连续序列
并且0其实对于我们的结果是没有贡献的,0只是充当了补充个数的功能,当我们0以外的数字已经达到了n的时候,我们用0来补充个数
比如n=3的时候,有一种序列 0 1 2这个时候0就是用来补充个数的
所以我们假设序列里面最后一个数是m,那么去重后的序列就是1/(0,1) 2 3...m
此时m是有个上限的,最多只能是接近sqrt(n)的一个数,我们可以用while循环求出这个数
然后我们枚举序列的最后一个数和当前序列能达到的总和,于是转换为一个DP问题
dp[i][j]表示用了0~i的数字所组成总和j的方案数(1~i的个数是没有限制的,类比完全背包=-=)
所以转移方程就是dp[i][j]=dp[i][j-i]+dp[i-1][j-i]分别表示用了0~i的数字所组成总和j-i的方案数和用了0~i-1的数字所组成总和j-i的方案数
也就是完全背包里面第一次取某个物品或者大于第一次取这个物品的两个状态了
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 50010
int dp[500][N];
int main()
{
int T,t=1;
long long n,m;
scanf("%d",&T);
while(T--)
{
scanf("%lld %lld",&n,&m);
int k=1;
while(k*(k+1)<=2*n) k++;
k--;
for(int i=0;i<=n;i++)
dp[0][i]=0;
for(int i=1;i<=k;i++)
dp[i][0]=0;
dp[0][0]=1;
for(int i=1;i<=k;i++)
{
for(int j=i;j<=n;j++)
{
dp[i][j]=(dp[i][j-i]+dp[i-1][j-i])%m;
}
}
long long ans=0;
for(int i=1;i<=k;i++)
ans=(ans+dp[i][n])%m;
printf("Case #%d: %lld\n",t++,ans);
}
return 0;
}

本文探讨了一个有趣的数学问题:如何计算满足特定条件的整数序列数量。条件包括序列中元素的和等于给定值n,同时序列必须是非递减的。文章提供了一种使用动态规划解决该问题的有效方法。
1217

被折叠的 条评论
为什么被折叠?



