1. 程式人生 > 實用技巧 >《演算法競賽進階指南》0x55環形與後效處理DP 環路運輸

《演算法競賽進階指南》0x55環形與後效處理DP 環路運輸

題目連結:https://www.acwing.com/problem/content/291/

題目給出的是一個環狀公路,公路上有n個點,每個點都有一個值w[i],點之間的距離就是從兩點沿著環的最短路徑,問最大的w[i]+w[j]+dis(i,j)是多少。

由於這個dis不會超過n/2,所以可以列舉一個點i,對[i-n/2,i-1]區間查詢w[i]-i的最大值。將環變成鏈狀處理即可,這裡由於一段區間計算的值只和端點有關,是一個滑動視窗求最值的問題,通過單調佇列可以在O(N)時間內求解。維護一個長度不超過len=n/2而且單調下降的序列的索引。

單調佇列中,假設k<j<i且維護的屬性值T[k]<T[j],那麼在不失更好的決策的情況下是不會保留k的,因為明顯j更大而且j更加靠近i。

程式碼:

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 2000010;
int w[maxn];
int q[maxn];
int n;

int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&w[i]);
        w[i+n]=w[i];
    }
    int l=1,r=1;
    int len=n/2;
    int ans=-1;
    
for(int i=1;i<=n*2;i++){ if(l<=r && q[l]<i-len)l++; ans=max(ans,w[i]+w[q[l]]+i-q[l]); while(l<=r && w[q[r]]-q[r]<=w[i]-i)r--; q[++r]=i; } cout<<ans<<endl; return 0; }