120718 测试 NOIP 模拟题 T3 最大数列
题面
分析
不说怎么暴力,因为暴力的难度与得分成正比
正解动归
设
:区间[1,i]的最大连续和(最大子区间和)
:区间[i,n]的最大连续和
(1<=i<=n)
那么易得
而和的维护可以再次写出方程
l[i-1]意为区间[1,i]的最大连续和不以i结尾,sum[i]-min(sum[j])意为区间[1,i]的最大连续和以i结尾
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.类题:最大连续子序列和