您的位置:首页 > 其它

hdu 5185 Equation(DP,思路)

2016-07-21 10:48 351 查看


Equation

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 492    Accepted Submission(s): 166


Problem Description

Gorwin is very interested in equations. Nowadays she gets an equation like this
x1+x2+x3+⋯+xn=n,
and here

0≤xi≤nfor1≤i≤nxi≤xi+1≤xi+1for1≤i≤n−1

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.

 

Input

Multi test cases. The first line of the file is an integer T indicates
the number of test cases.

In the next T lines,
every line contain two integer n,m.

[Technical Specification]
1≤T<20
1≤n≤50000
1≤m≤1000000000

 

Output

For each case output should occupies one line, the output format is Case #id: ans, here id is the data number starting from 1, ans is the result you are expected to output.

See the samples for more details.

 

Sample Input

2
3 100
5 100

 

Sample Output

Case #1: 2
Case #2: 3

题意:从1~n里面选出n个数要求满足x1+x2+...xn=n并且xi<=x(i+1)<=xi+1,结果对m取模,问一共有几种可能序列

思路:首先分析该条件可以发现该序列一定不能从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]
;
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]
)%m;
printf("Case #%d: %lld\n",t++,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: