hdu 5185 Equation(DP,思路)

来源:互联网 发布:淘宝修改送货地址 编辑:程序博客网 时间:2024/06/08 08:57

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
0xinfor1inxixi+1xi+1for1in1

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]
1T<20
1n50000
1m1000000000
 

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
23 1005 100
 

Sample Output
Case #1: 2Case #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 50010int 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;}




0 0
原创粉丝点击