CH5501 环路运输(单调栈)

传送门

思路:

  遇到一个环,用正常人类的思想就先把环从中间截断然后将其补成2*n长度的链。环上的最小距离换到链上就是i以n/2为半径范围内的点(画图肉眼可见)。由于两个点是等价的,所以我们考虑有序对(i,j){1<=j<i<=2*n&&i-j<=n/2}

  题目要求最大的a[i]+a[j]+dis(i,j)。在上述条件下,dis(i,j)=i-j。那么就是要求a[i]+a[j]+i-j,只要枚举i,得到最大的a[j]-j就好了,考虑j的取值范围[i-n/2,i-1],用单调栈维护a[i]-j

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int a[2*maxn],q[2*maxn],tail,head,ans;
int main()
{
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++)        scanf("%d",&a[i]);
    for(int i=1+n;i<=2*n;i++)    a[i]=a[i-n];
    int c=n/2;
    for(int i=1;i<=c;i++){
        while(tail&&a[q[tail]]-q[tail]<=a[i]-i)
            tail--;
        q[++tail]=i;
    }
    head=1;
    ans=a[c+1]+c+1-q[head]+a[q[head]];
    for(int i=2;i<=n;i++){
        int id=c-1+i;
        while(head<=tail&&q[head]<i)    head++;
        while(tail>=head&&a[q[tail]]-q[tail]<=a[id]-id)    tail--;
        q[++tail]=id;
        ans=max(ans,a[id+1]+id+1-q[head]+a[q[head]]);
    }
    cout<<ans<<endl;
}
View Code
原文地址:https://www.cnblogs.com/r138155/p/12642143.html