校赛问题 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;
}    
posted @ 2020-07-25 00:16  ANhour  阅读(276)  评论(0编辑  收藏  举报