校赛问题 G: Brannn爱旅游(前缀/后缀最大值)
题目大意:给出数组A[],数据范围n<=50000,求a[i]+a[j]+i-j(j>i)的最大值...
这似乎是字节跳动的面试题来着...
题解:数组倒着看,对于每个a[j]-j,只要找到一个a[i]+i的最大值就好了。i∈[1,j-1]。所以处理和前缀最大值就可以。时间复杂度为O(n),我当时竟然写的线段树求的区间最大值我个憨批。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 50010
using namespace std;
int n;
int a[N];
struct Tree
{
int l,r,v;
}tr[N*4];
void build(int now,int l,int r)
{
tr[now].l=l;
tr[now].r=r;
if(l==r)
{
tr[now].v=a[l]+l;
return;
}
int mid=(l+r)>>1;
build(now*2,l,mid);
build(now*2+1,mid+1,r);
tr[now].v=max(tr[now*2].v,tr[now*2+1].v);
}
int get_max(int now,int L,int R)
{
if(tr[now].l<=L&&tr[now].r<=R) return tr[now].v;
int mid=(tr[now].l+tr[now].r)>>1;
if(R<=mid)return get_max(now*2,L,R);
if(L>mid) return get_max(now*2+1,L,R);
return max(get_max(now*2,L,mid),get_max(now*2+1,mid+1,R));
}
int main()
{
scanf("%d",&n);
int ans=0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
for(int i=n;i>1;i--)
{
ans=max(ans,a[i]-i+get_max(1,1,i-1));
}
printf("%d\n",ans);
return 0;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 52100
using namespace std;
int n,ans;
int a[N];
int p[N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
p[i]=max(p[i-1],a[i]+i);
}
// for(int i=1;i<=n;i++) cout<<p[i]<<" ";
for(int i=2;i<=n;i++)
{
ans=max(ans,a[i]-i+p[i-1]);
}
cout<<ans<<endl;
return 0;
}