Max Sum Plus Plus

Problem Description
Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now you are faced with a more difficult problem.

Given a consecutive number sequence S 1, S 2, S 3, S 4 ... S x, ... S n (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ S x ≤ 32767). We define a function sum(i, j) = S i + ... + S j (1 ≤ i ≤ j ≤ n).

Now given an integer m (m > 0), your task is to find m pairs of i and j which make sum(i 1, j 1) + sum(i 2, j 2) + sum(i 3, j 3) + ... + sum(i m, j m) maximal (i x ≤ i y ≤ j x or i x ≤ j y ≤ j x is not allowed).

But I`m lazy, I don't want to write a special-judge module, so you don't have to output m pairs of i and j, just output the maximal summation of sum(i x, j x)(1 ≤ x ≤ m) instead. ^_^
 

Input
Each test case will begin with two integers m and n, followed by n integers S 1, S 2, S 3 ... S n.
Process to the end of file.
 

Output
Output the maximal summation described above in one line.
 

Sample Input
 
 
1 3 1 2 32 6 -1 4 -2 3 -2 3
 

Sample Output
 
 
68
很明显是dp但是状态转移并不是很好找。其次不能奢侈的开空间需要降维,如何实现并不困难因为每次转移只与上一次有关,并且题目不考虑中间态那么就需要不断更新本次的值和上一次的值。
#include<iostream>
#include<cstdio>
using namespace std;
const int MAX=1000001;
int dp[2][MAX];
int w[MAX];
int sum[MAX];
int cmax(int a,int b)//求最大值
{
	return a>b?a:b;
}
int main()
{
	int i,k;
	int m,n;
	while(scanf("%d%d",&m,&n)>0)
	{
		scanf("%d",&k);
		sum[i]=sum[i-1]+k;
		dp[0][i]=0;
	}
	int t=1;
       for(i=1;i<=m;i++)//i表示在取i段,自然i<=m;
	   {
		   
		   for(k=i;k<=n;k++)//为什么k从i开始?dp[i][k](k<i)是没有意义的!
		   {
			   if(i==k)
			   dp[t][k]=w[k]=sum[k];//从k个数中取k段的最大值是前k个数的和
			   else
			   {
				   w[k]=cmax(dp[1-t][k-1],w[k-1])+sum[k]-sum[k-1];//w[k]表示k个元素取i段,a[k]必须取时的最大值
		//w[i][k]=max(b[i-1][k-1],w[i][k-1])+a[k];
				   dp[t][k]=cmax(dp[t][k-1],w[k]);//dp[t][k]表示在a[k]可取可不取这两种情况下取得的最大值
				   //自然,dp[t][k]记录的就是在前k个元素中取i段时取得的最大值!
			   }
		   }
		   t=1-t;//t在1,0之间交替变换
  //为什么要交替呢?这是为了节省空间
  //仔细观察递归式
  //w[i][k]=max(b[i-1][k-1],w[i][k-1])+a[k];
  //b[i][k]=max(b[i][k-1],w[i][k]);
  //我们发现,对于取i段,w[i][j]只与b[i-1][k-1]和w[i][k-1]有关,与之前的那一些项没有关系
  //因此我们数组可以开小一点,用更新来覆盖掉前面的值!
	   }
	   cout<<dp[m%2][n]<<endl;//奇次轮还是偶次轮
	return 0;
}
	


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值