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

题面

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

分析

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

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

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

r[i]=max(r[i+1],sum[i]min(sum[j])),1&lt;=i&lt;=n,i&lt;j&lt;=nr[i]=max(r[i+1],sum[i]-min(sum[j])),1&lt;=i&lt;=n,i&lt;j&lt;=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.类题:最大连续子序列和

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