HDU1024Max Sum Plus Plus (dp)

题目网址点击打开链接

题目没有m的范围

没有想出来,然后看到网上的题解

题意

给n个数,将其分为m部分,各部分之间不能有交叉重叠,求最大和

思路

dp[i][j]表示前j个数分为i部分的最大和,则
dp[i][j] = max(dp[i][j-1] + a[j], dp[i-1][k] + a[j]) i-1<=k<=j-1
前者是将第j个数加入到第i部分,后者是将第j个数做为第i部分的第一个数。

两个关键点

  1. 因为题目n值范围过大,显然二维数组不行。
    而d[i][x]只与d[i-1][x]有关,所以可以将其降低至一维。
    即dp[j]表示前j个数所分段后的和。
  2. 因为dp[i-1][k]的取值需要一重循环,极有可能导致超时,所以使用数组max存储当前层的最大值,以供下一层求值使用。
    dp[j] = max(dp[j-1] + a[j], max[j-1] + a[j])

然后是代码:

有个问题我以为是要用longlong ,结果不用,long long 的话要交g++编译器,不然会超时

//#include <iostream>
//#include<algorithm>
//#include<cstdio>
//#include<cstring>
//#include<cmath>
//#include<string>
//
//using namespace std;
//const int maxn=1e6+5;
//long long dp[maxn];
//long long maxd[maxn];
//long long s[maxn];
//int main()
//{
//    int m,n;
//    long long minn=-(1e6*(long long)32768);
//    while(~scanf("%d%d",&m,&n))
//    {
//        for(int i=1;i<=n;i++)
//            scanf("%lld",&s[i]);
//        memset(maxd,0,sizeof(maxd));//0组必须全部置零,因为1组会用到0时的状态
//        dp[0]=0;
//        long long maxx=minn;
//        for(int i=1;i<=m;i++)
//        {
//            maxx=minn;
//            for(int j=i;j<=n;j++) //注意是j位必须从i部分开始,因为要分为i部分,至少到j位
//            {
//
//                dp[j]=max(dp[j-1]+s[j],maxd[j-1]+s[j]);
//                //此时更新j-1的位置,将j-1滚为i部分的值,这样既可以保证下一个j时maxd[j-1]还为i-1部分的值
//                maxd[j-1]=maxx;
//                maxx=max(maxx,dp[j]);
//            }
//        }
//        //注意此处不能写dp[n],因为分为的m组不一定包含n,应该是分为m部分中,各个位置结尾的最大dp[j]
//        printf("%lld\n",maxx);
//    }
//    return 0;
//}
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>

using namespace std;
const int maxn=1e6+5;
int dp[maxn];
int maxd[maxn];
int s[maxn];
int main()
{
    int m,n;
    int minn=-(1e8);
    while(~scanf("%d%d",&m,&n))
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&s[i]);
        memset(maxd,0,sizeof(maxd));//0组必须全部置零,因为1组会用到0时的状态
        dp[0]=0;
        int maxx=minn;
        for(int i=1;i<=m;i++)
        {
            maxx=minn;
            for(int j=i;j<=n;j++) //注意是j位必须从i部分开始,因为要分为i部分,至少到j位
            {

                dp[j]=max(dp[j-1]+s[j],maxd[j-1]+s[j]);
                //此时更新j-1的位置,将j-1滚为i部分的值,这样既可以保证下一个j时maxd[j-1]还为i-1部分的值
                maxd[j-1]=maxx;
                maxx=max(maxx,dp[j]);
            }
        }
        //注意此处不能写dp[n],因为分为的m组不一定包含n,应该是分为m部分中,各个位置结尾的最大dp[j]
        printf("%d\n",maxx);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/sinat_36215255/article/details/80427551