[codeforces 1359D] Yet Another Yet Another Task 当前元素为峰值进行蚕食/连续和的动归dp

Educational Codeforces Round 88 (Rated for Div. 2)  参赛人数19992

[codeforces 1359D]    Yet Another Yet Another Task   当前元素为峰值进行蚕食/连续和的动归dp

总目录详见https://blog.csdn.net/mrcrack/article/details/103564004

在线测评地址https://codeforces.com/contest/1359/problem/D

方法一:当前元素为峰值进行蚕食

此种办法,对应该题的第一直觉,找该数为最大值的连续和

ProblemLangVerdictTimeMemory
D - Yet Another Yet Another Task GNU C++17Accepted46 ms1000 KB

样例模拟如下

5
5 -2 10 -1 4

位置0  1  2  3  4 5 6
数值35 5 -2 10 -1 4 35

以位置1处的数值5为峰值,
统辖的位置区间是[1,2]
峰值5左侧最大连续和是0(初始情况,左侧可什么都不选,可对应最小值0)
峰值5右侧最大连续和是0(初始情况,右侧可什么都不选,可对应最小值0,故不选-2)
对应的位置区间[1,2],扣除峰值位置1的数值最大连续和是0+0=0

以位置2处的数值-2为峰值,
统辖的位置区间是[2,2]
峰值-2左侧最大连续和是0(初始情况,左侧可什么都不选,可对应最小值0)
峰值-2右侧最大连续和是0(初始情况,右侧可什么都不选,可对应最小值0)
对应的位置区间[2,2],扣除峰值位置2的数值最大连续和是0+0=0

以位置3处的数值10为峰值,
统辖的位置区间是[1,5]
峰值10左侧最大连续和是3(选择位置区间[1,2])
峰值10右侧最大连续和是3(选择位置区间[4,5])
对应的位置区间[1,5],扣除峰值位置3的数值最大连续和是3+3=6

以位置4处的数值-1为峰值,
统辖的位置区间是[4,4]
峰值-1左侧最大连续和是0(初始情况,左侧可什么都不选,可对应最小值0)
峰值-1右侧最大连续和是0(初始情况,右侧可什么都不选,可对应最小值0)
对应的位置区间[4,4],扣除峰值位置2的数值最大连续和是0+0=0


以位置5处的数值4为峰值,
统辖的位置区间是[4,5]
峰值4左侧最大连续和是0(初始情况,左侧可什么都不选,可对应最小值0,故不选-1)
峰值4右侧最大连续和是0(初始情况,右侧可什么都不选,可对应最小值0)
对应的位置区间[1,5],扣除峰值位置3的数值最大连续和是0+0=0

综上所述,最大值是6

 样例进一步的模拟

注意a[1]=a[n+1]=35是为了边界的处理而设置的。

8
5 2 5 3 -30 -30 6 9

位置0  1  2  3  4   5   6 7 8 9
数值35 5  2  5  3 -30 -30 6 9 35

以位置1处的数值5为峰值,
统辖的位置区间是[1,2]
峰值5左侧最大连续和是0(初始情况,左侧可什么都不选,可对应最小值0)
峰值5右侧最大连续和是2(选择位置区间[2,2])
对应的位置区间[1,2],扣除峰值位置1的数值最大连续和是0+2=2
同时记录,位置1对应左侧区间最大连续和prem1[1]=0

以位置2处的数值2为峰值,
统辖的位置区间是[2,2]
峰值2左侧最大连续和是0(初始情况,左侧可什么都不选,可对应最小值0)
峰值2右侧最大连续和是0(初始情况,右侧可什么都不选,可对应最小值0)
对应的位置区间[2,2],扣除峰值位置2的数值最大连续和是0+0=0
同时记录,位置2对应左侧区间最大连续和prem1[2]=0

以位置3处的数值5为峰值,
统辖的位置区间是[2,6]
峰值5左侧最大连续和是2(选择位置区间[2,2])
注意,左侧遇到a[1]=5,考虑a[1]+prem1[1]=5,对左侧最大连续和有贡献,
故此时,左侧最大连续和是2+5=7;

峰值5右侧最大连续和是3(选择位置区间[4,4])
对应的位置区间[2,4],扣除峰值位置3的数值最大连续和是7+3=10
同时记录,位置3对应左侧区间最大连续和prem1[3]=7



以位置4处的数值3为峰值,
统辖的位置区间是[4,6]
峰值3左侧最大连续和是0(初始情况,左侧可什么都不选,可对应最小值0)
峰值3右侧最大连续和是0(初始情况,右侧可什么都不选,可对应最小值0,故不选位置区间[5,6])
对应的位置区间[4,6],扣除峰值位置4的数值最大连续和是0+0=0
同时记录,位置4对应左侧区间最大连续和prem1[4]=0

以位置5处的数值-30为峰值,
统辖的位置区间是[5,5]
峰值4左侧最大连续和是0(初始情况,左侧可什么都不选,可对应最小值0)
峰值4右侧最大连续和是0(初始情况,右侧可什么都不选,可对应最小值0)
对应的位置区间[5,5],扣除峰值位置5的数值最大连续和是0+0=0
同时记录,位置5对应左侧区间最大连续和prem1[5]=0


以位置6处的数值-30为峰值,
统辖的位置区间是[6,6]
峰值6左侧最大连续和是0(初始情况,左侧可什么都不选,可对应最小值0)
注意,左侧遇到a[5]=-30,考虑a[5]+prem1[5]=-30,对左侧最大连续和没有贡献,
故此时,左侧最大连续和是0;

峰值6右侧最大连续和是0(初始情况,右侧可什么都不选,可对应最小值0)
对应的位置区间[6,6],扣除峰值位置6的数值最大连续和是0+0=0
同时记录,位置6对应左侧区间最大连续和prem1[6]=0


以位置7处的数值6为峰值,
统辖的位置区间是[1,7]
峰值6左侧最大连续和是0(初始情况,左侧可什么都不选,可对应最小值0,故不选位置区间[1,6])

峰值6右侧最大连续和是0(初始情况,右侧可什么都不选,可对应最小值0)
对应的位置区间[1,7],扣除峰值位置7的数值最大连续和是0+0=0
同时记录,位置7对应左侧区间最大连续和prem1[7]=0

以位置8处的数值9为峰值,
统辖的位置区间是[1,8]
峰值9左侧最大连续和是0(初始情况,左侧可什么都不选,可对应最小值0,故不选位置区间[1,7])

峰值9右侧最大连续和是0(初始情况,右侧可什么都不选,可对应最小值0)
对应的位置区间[1,8],扣除峰值位置8的数值最大连续和是0+0=0
同时记录,位置7对应左侧区间最大连续和prem1[8]=0

综上所述,最大值是10

AC代码如下

#include <cstdio>
#include <algorithm>
#define maxn 100010
using namespace std;
int a[maxn],prem1[maxn],ans;//prem1[i]记录峰值a[i]之前的最大连续和
int main(){
	int n,i,j;
	scanf("%d",&n);
	for(i=1;i<=n;i++)scanf("%d",&a[i]);
	a[0]=a[n+1]=35;//边界设置
	for(i=1;i<=n;i++){//a[i]为当前峰值
		int s1=0,s2=0,m1=0,m2=0;
		for(j=i-1;a[j]<=a[i];j--){//i的左侧
			if(a[j]==a[i]){//找到上一个峰值a[j]==a[i]
				m1=max(m1,s1+a[j]+prem1[j]);//s1+a[j]+prem1[j]表示合并上一个峰值数据.因prem1[j]>=0,故s1+arr[j]+prem1[j]>=s1+arr[j]
				break;
			}
			s1+=a[j];//s1记录连续和
			m1=max(m1,s1);//找连续和中的最大值
		}
		for(j=i+1;a[i]>a[j];j++){//i的右边最大的值比arr[i]小
			s2+=a[j];
			m2=max(m2,s2);
		}
		ans=max(ans,m1+m2);
		prem1[i]=m1;//算法最神奇之处,在于prem1[]数组的引入
	}
	printf("%d\n",ans);
	return 0;
}

方法二:连续和的动归dp

此种办法,对应最大连续和的常见处理手法

ProblemLangVerdictTimeMemory
D - Yet Another Yet Another Task GNU C++17Accepted61 ms1000 KB

样例模拟如下

5
5 -2 10 -1 4

位置1  2  3  4 5
数值5 -2 10 -1 4

以元素值4为最大值,可找到最大连续和的位置区间[3,5]
对应连续和是10-1+4=6,
扣除最大值4,对应结果6-4=2

以元素值5为最大值,可找到最大连续和的位置区间[1,2]
对应连续和是5-2=3,
扣除最大值5,对应结果3-5=-2

以元素值10为最大值,可找到最大连续和的位置区间[1,5]
对应连续和是5-2+10-1+4=16
扣除最大值10,对应结果16-10=6

综合上述情况,输出最大值6

样例进一步的模拟

8
5 2 5 3 -30 -30 6 9

位置1  2  3  4   5   6 7 8
数值5  2  5  3 -30 -30 6 9


以元素值2为最大值,可找到最大连续和的位置区间[2,2]
对应连续和是2,
扣除最大值2,对应结果2-2=0

以元素值3为最大值,可找到最大连续和的位置区间[4,4]
对应连续和是3,
扣除最大值3,对应结果3-3=0

以元素值5为最大值,可找到最大连续和的位置区间[1,4]
对应连续和是5+2+5+3=15
扣除最大值5,对应结果15-5=10

以元素值6为最大值,可找到最大连续和的位置区间[7,7]
对应连续和是6,
扣除最大值6,对应结果6-6=0

以元素值9为最大值,可找到最大连续和的位置区间[7,8]
对应连续和是6+9=15,
扣除最大值9,对应结果15-9=6

综合上述情况,输出最大值10

AC代码如下

#include <cstdio>
#include <algorithm>
#define maxn 100010
using namespace std;
int n,dp[maxn],a[maxn],MX,ans;
int main(){
	int i,mx;
	scanf("%d",&n);
	for(i=1;i<=n;i++)scanf("%d",&a[i]),MX=max(MX,a[i]);
	for(mx=1;mx<=MX;mx++){//根据选定的最大数据进行枚举
		for(i=1;i<=n;i++)dp[i]=0;//初始化
		for(i=1;i<=n;i++){
			if(a[i]<=mx&&dp[i-1]+a[i]>0)dp[i]=dp[i-1]+a[i];
			else dp[i]=0;//因a[i]>mx或者dp[i-1]+a[i]<=0,请注意,此时的a[i]被抛弃了,即将开始新的一段连续和
			ans=max(ans,dp[i]-mx);//扣除最大值
		}
	}
	printf("%d\n",ans);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值