您的位置:首页 > 其它

hdu 5185 Equation && BestCoder Round #32

2015-03-10 20:21 330 查看
题目:

x[1]+x[2]+x[3]+…+x
=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
[m]代表当前x1,x2....xi中最大值为m(m <= sqrt(n)),sum(xi)为n(n <= 50000)的值存在多少种

情况,状态转移方程也可以顺势写出,dp
[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]
) % m;
            memset(dp[j & 1],0,sizeof(dp[j & 1]));
        }
        printf("Case #%d: %d\n",kcas,ans);
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: