hdu 5185 Equation && BestCoder Round #32

题目: 
x[1]+x[2]+x[3]+…+x[n]=n, 这里 
0 <= x[i] <= n && 1 <= i <= n 
x[i] <= x[i+1] <= x[i]+1 && 1 <= i <= n-1 
对于一个给定的n,Gorwin想要知道有多少xi的组合满足上述等式。由于结果比较大,输出答案对m取余的结果就行。


思路:1.观察发现数字种类只可能有srqt(n)种

          2.发现第一个数只能从0或者1开始,想试试用dp来做这个题。

         3.dp[n][m]代表当前x1,x2....xi中最大值为m(m <= sqrt(n)),sum(xi)为n(n <= 50000)的值存在多少种

况,状态转移方程也可以顺势写出,dp[n][m] = dp[n - m][m] + dp[n - m][m - 1](只是一个帮助思考的递推方程,

并不是最终的递推方程)。

  4.但是发现没法了解究竟i是多大?!。。也就是没法记录已经存在多少个xi了

  5.思考后发现是不是可以不去管已经存在多少个xi了,因为如果假设1开始,i最大不会超过n,所以可以不必理

会存在多少个xi了,如果xi总数少于n直接用前缀0补齐就行了

  6.可以观察转移方程再优化节约一维空间

总结:最近考虑了很多问题发现,应该规范思考问题的方式,比如

1.首先要明确要思考的的目标

2.其次先从最简单的情况开始考虑(比如从枚举开始考虑,不要轻易为题目定性),争取做到不遗漏

  3.将步骤写在纸上就可以避免重复思考,并且可以发现思维漏洞

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define MAXM 50005
int dp[2][MAXM];
int main()
{
    int _,n,m;
    for(int kcas = scanf("%d",&_);kcas <= _;kcas++)
    {
        scanf("%d%d",&n,&m);
        int l = sqrt(2.0 * n + 1);
        memset(dp,0,sizeof(dp));
        dp[1][1] = 1;
        int ans = 0;
        for(int j = 1;j <= l;j++)
        {
            for(int i = 1;i <= n && i + j <= n;i++)
            {
                dp[j & 1][i + j] = (dp[j & 1][i] + dp[j & 1][i + j]) % m;
                dp[(j + 1) & 1][i + j + 1] = (dp[j & 1][i] + dp[(j + 1) & 1][i + j + 1]) % m;
            }
            ans = (ans + dp[j & 1][n]) % m;
            memset(dp[j & 1],0,sizeof(dp[j & 1]));
        }
        printf("Case #%d: %d\n",kcas,ans);
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值