;
题目没有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部分的第一个数。两个关键点
- 因为题目n值范围过大,显然二维数组不行。
而d[i][x]只与d[i-1][x]有关,所以可以将其降低至一维。
即dp[j]表示前j个数所分段后的和。- 因为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;
}