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
方法一:当前元素为峰值进行蚕食
此种办法,对应该题的第一直觉,找该数为最大值的连续和
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
D - Yet Another Yet Another Task | GNU C++17 | Accepted | 46 ms | 1000 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
此种办法,对应最大连续和的常见处理手法
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
D - Yet Another Yet Another Task | GNU C++17 | Accepted | 61 ms | 1000 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;
}