hdu 1024
链接
[https://vjudge.net/contest/256508#problem/B]
题意
给你n个数字的数组,让你找m个子段,使得和最大
分析
这题算是看了两三天才明白,这个意思,还是太菜了。
首先定义状态转移方程
dp[i][j]表示,选取第j个数字的情况下,分成i个子段的最大和
那么对于a[j]这个位置有两种情况,就是和其他数字组成第i子段,或者单独作为第i子段
dp[i][j]=Max(dp[i][j-1]+a[j] , max( dp[i-1][k] ) + a[j] ) 0<k<j
但由于n很大而且m未知,二维的肯定会炸内存的,
发现max( dp[i-1][k] )可以用一个一维pre[i-1]的来保存分成i-1段的最大和。
相当于空间优化了,也就是他们说的滚动数组,哎还是太菜了,看代码吧
代码
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
#define ll long long
const int N=1e6+10;
int dp[N],pre[N];
//dp[i]表示选取第i个的情况下,分成j段的最大和
//pre[i]表示前i个数,分成j段的最大值
int a[N];
int main(){
int n,m;
freopen("in.txt","r",stdin);
while(cin>>m>>n){
for(int i=1;i<=n;i++){
cin>>a[i];
dp[i]=0;
pre[i]=0;
}
int ma;
for(int i=1;i<=m;i++)
{
ma=-1e9;
for(int j=i;j<=n;j++)
{
//cout<<dp[j-1]<<' '<<pre[j-1]<<endl;
dp[j]=max(dp[j-1]+a[j],pre[j-1]+a[j]);
//这里的pre[j-1]是上一层的pre[j-1],也就是分成i-1子段的最大值
//选取第j个时分成当前i子段的最大值
pre[j-1]=ma;
//cout<<dp[j]<<' '<<pre[j-1]<<endl;
//这里的pre[j-1]是到第j-1个数当前层的最大值,也就是分成i子段的最大值
if(dp[j]>ma)
ma=dp[j];
//通过对比取不取第j个而获得最大值
}
}
cout<<ma<<endl;
}
return 0;
}

浙公网安备 33010602011771号