120718 测试 NOIP 模拟题 T3 最大数列

题面

在这里插入图片描述

分析

不说怎么暴力,因为暴力的难度与得分成正比
正解动归

l [ i ] l[i] l[i]:区间[1,i]的最大连续和(最大子区间和)
r [ i ] r[i] r[i]:区间[i,n]的最大连续和
(1<=i<=n)
那么易得
S = m a x ( l [ i ] + r [ i + 1 ] ) S=max(l[i]+r[i+1]) S=max(l[i]+r[i+1])
l [ i ] l[i] l[i] r [ i ] r[i] r[i]的维护可以再次写出方程
l [ i ] = m a x ( l [ i − 1 ] , s u m [ i ] − m i n ( s u m [ j ] ) ) , 1 &lt; = i &lt; = n , j &lt; i l[i]=max(l[i-1],sum[i]-min(sum[j])),1&lt;=i&lt;=n,j&lt;i l[i]=max(l[i1],sum[i]min(sum[j])),1<=i<=n,j<i

l[i-1]意为区间[1,i]的最大连续和不以i结尾,sum[i]-min(sum[j])意为区间[1,i]的最大连续和以i结尾

r [ i ] = m a x ( r [ i + 1 ] , s u m [ i ] − m i n ( s u m [ j ] ) ) , 1 &lt; = i &lt; = n , i &lt; j &lt; = n r[i]=max(r[i+1],sum[i]-min(sum[j])),1&lt;=i&lt;=n,i&lt;j&lt;=n r[i]=max(r[i+1],sum[i]min(sum[j])),1<=i<=n,i<j<=n

l[i-1]意为区间[i,n]的最大连续和不以i开头,sum[i]-min(sum[j])意为区间[1,i]的最大连续和以i开头

sum[i]指1到i的前缀和
sum[i]-min(sum[j])其实就是区间和

code

#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(int i=start;i<=end;i++)
#define anti_loop(i,start,end) for(int i=start;i>=end;i--)
#define clean(arry,num); memset(arry,num,sizeof(arry));
#define min(a,b) ((a<b)?a:b)
#define max(a,b) ((a>b)?a:b)
#define ll long long
int n;
const int maxn=100000+100;
int a[maxn];
ll l[maxn];
ll r[maxn];
inline int read()
{
	bool neg=false;int res=0;char r=getchar();
	while(r>'9'||r<'0'){if(r=='-')neg=true;r=getchar();}
	while(r>='0'&&r<='9'){res=res*10+r-'0';r=getchar();}
	return (neg)?-res:res;
}
int main()
{
	//freopen("datain2.txt","r",stdin);
	n=read();clean(a,0);clean(l,0);clean(r,0);
	ll sum=0,minsum=0;r[n+1]=l[0]=-0x7f7f7f;
	//注意要处理好r[n+1]=l[0],因为在计算r[n],l[1]时要用到其值(其实是不想特判啦)
	loop(i,1,n)
	{
		a[i]=read();
		sum+=a[i];//
		l[i]=(i==1)?a[i]:max(l[i-1],sum-minsum);
		minsum=min(minsum,sum);
		//也要注意维护min(sum[j]),j<i,不可取等,故minsum要在计算出第一个数后才更新
	}
	sum=0;minsum=0;
	anti_loop(i,n,1)
	{
		sum+=a[i];
		r[i]=(i==n)?a[i]:max(r[i+1],sum-minsum);
		minsum=min(minsum,sum);
	}
	//ll maxx=0;不要这样写!!有负数!!
	ll maxx=-0x9f9f9f;
	loop(i,1,n)maxx=max(maxx,l[i]+r[i+1]);
	printf("%lld",maxx);
	return 0;
}

学到的东西

1.类题:最大连续子序列和

在这里插入图片描述
其实本题就是图中问题的一个扩展,我们如果用图中所讲的方法,从左向右求一次dp[i](意义同图),再从右向左求一次dp2[i](dp2[i]指以a[i]作为起点的连续序列最大和),然后枚举i求max,其实也是可以得到本题的解的,只是可能要麻烦一些罢了
方程:
d p [ i ] = m a x ( d p [ i − 1 ] + A [ i ] , A [ i ] ) dp[i]=max(dp[i-1]+A[i],A[i]) dp[i]=max(dp[i1]+A[i],A[i])
d p 2 [ i ] = m a x ( d p [ i + 1 ] + A [ i ] , A [ i ] ) dp2[i]=max(dp[i+1]+A[i],A[i]) dp2[i]=max(dp[i+1]+A[i],A[i])
S = m a x ( d p [ i ] + d p 2 [ i ] ) S=max(dp[i]+dp2[i]) S=max(dp[i]+dp2[i])
这样应该可以的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AndrewMe8211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值