CH5501 环路运输

题意

描述

在一条环形公路旁均匀地分布着N座仓库,编号为1~N,编号为 i 的仓库与编号为 j 的仓库之间的距离定义为 dist(i,j)=min⁡(|i-j|,N-|i-j|),也就是逆时针或顺时针从 i 到 j 中较近的一种。每座仓库都存有货物,其中编号为 i 的仓库库存量为 A_i。在 i 和 j 两座仓库之间运送货物需要的代价为 A_i+A_j+dist(i,j)。求在哪两座仓库之间运送货物需要的代价最大。1≤N≤10^6,1<=Ai<=10^7。

输入格式

第一行一个整数N,第二行N个整数A1~AN。

输出格式

一个整数,表示最大代价。

样例输入

5
1 8 6 2 5

样例输出

15

分析

参照SSL_ZYC的题解。

环上的DP固然不好做,可以先把环拆成链,再拷贝一份。成为一条长度为\(2n\)的链。

那么接下来的DP就再链上DP就可以了。
首先对于两点的距离,取的是\(a[i]+a[j]+\min(|i-j|,|n-(i-j)|)\)。也就是环上顺时针和逆时针的距离的最小值。现在变成了链,就要发生改变。
很容易发现,顺时针和逆时针的最小值就是看看\(|i-j|\)是否超过了\(n/2\),如果没有超过,那么肯定顺时针更优,否则逆时针更优。
那么将环拆成链之后,顺时针还是在原来的环上(即$ i,j\leq n\(),就可以直接求出答案。否则\)j\(就会超过\)n\(。 如果是逆时针,那么链拷贝一份的作用求起到了。那么我们用\)|i-j|\(变成\)|j-i|\(,之后又知道\)j=j+n\(,那么就有\)|i-j|=|j-i|=|j+n-i|$。那么也变成了一条链。就可以求出答案了。

时间复杂度\(O(n^2)\),必须优化。我们发现要求最大值,那么就可以用单调队列优化,维护在区间范围内的最大值,每次至直接\(O(1)\)求最大值即可。时间复杂度\(O(n)\)

代码

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;rg char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
    while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
    return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;

co int N=2e6+1;
int a[N],q[N],n,ans;
int main(){
//  freopen(".in","r",stdin),freopen(".out","w",stdout);
    read(n);
    for(int i=1;i<=n;++i) a[n+i]=read(a[i]);
    int l=1,r=1;
    q[1]=1;
    for(int i=2;i<=n<<1;++i){
        while(l<=r&&i-q[l]>n/2) ++l;
        ans=std::max(ans,a[i]+a[q[l]]+i-q[l]);
        while(l<=r&&a[i]-i>=a[q[r]]-q[r]) --r;
        q[++r]=i;
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/10667028.html