hdu 5185 动态规划 分析降低复杂度

这题说的是

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取余的结果就行。

n<=50000

经过分析我们知道第一个数必须是 0  或者 1 ,如果是0 那么我们分析,第一个开始为1 的数字, 后面必须连续到结尾都是大于等于1 的个数,这么想前面的那些前导0将变得毫无意义,只是连续非0长度的个数,我们在计算中会计算出来的。现在我们有一个方案 dp[i][j] 表示前n项到达j的方案 数, 这样我们 有 n*n*n 的状态转移, 好了现在这个复杂度过大,我们可以想办法把它降下来,我们知道连续的数字 各个都不同最多才 sqrt(n)个,现在就降了一点了, 再想想我们摈弃了 0 那么意思说第一个数是从1开始的,那么我们就不用害怕他会使用超过n个数字来达到和为n 我们知道最多也就是使用n个分别都为1 ,其余的都得小于1,那么现在我们是不是又降了最外层的一个n , 现在复杂度变成了 nsqrt(n);

我们再整理一下, dp[i][j] 表示使用1-i个数字组成和为j的个数,(因为我们可以不讨论使用了多少个数字,因为他肯定不会超过n)时间复杂度刚好

dp[i][j]=( dp[i][j-i] + dp[i-1][j-i] )%m

//
//  main.cpp
//  hdu5185c++
//
//  Created by opas on 15/3/15.
//  Copyright (c) 2015年 opas. All rights reserved.
//

#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
using namespace std;
typedef long long LL;
const int maxn = 50010;
const int maxm =321;
int dp[maxm][maxn];
int main(int argc, const char * argv[]) {
    // insert code here...
    int cas;
    scanf("%d",&cas);
    int n,m;
    for(int cc =1; cc<= cas; ++cc){
        scanf("%d%d",&n,&m);
        
        memset(dp, 0, sizeof(dp));
         int k=1,G=n;
        while(k*(1+k)<=G*2) k++;
        k--;
        dp[0][0]=1;
        for(int i=1; i<=k; ++i)
            for(int j=i; j <= n ; ++ j ){
                dp[i][j]= (dp[i-1][j-i]+dp[i][j-i])%m;
            }
        int ans=0;
        for(int i=1; i <= k; ++i )
            ans= (ans+dp[i][n])%m;
        printf("Case #%d: %d
",cc, ans);
        
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Opaser/p/4343341.html