zoukankan      html  css  js  c++  java
  • $CH5501$ 环路运输 环形$+$单调队列

    CH

    Description

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

     

    Sol

    断环为链,再复制一段到末尾

    枚举i,我们只需要找到一个在[i-N/2,i-1]之间找到一个j使得(a[j]-j)最大,就求出了当前的最大代价.

    找j当然不能枚举(N的范围就在上面),可以用单调队列维护.

    具体来说,双端单调队列的队头放的是a[j]-j的最大值,以及j值(即它的序号),每次i++,把j超过范围(<i-N/2)的移出队列,把队列里比a[i-1]-(i-1)小的移出队列,再将a[i-1]-(i-1)加入队列,最后取出队头,即使当前a[j]-j的最大值.

    如果关于单调队列的部分不明白,建议做Luogu1886滑动窗口

    至于双端,用deque辣QwQ

    Code

     这题的code还是很好实现的 : ) 好久没有一遍过了QwQ

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<queue>
     4 #define Rg register
     5 #define il inline
     6 #define go(i,a,b) for(Rg int i=a;i<=b;++i)
     7 using namespace std;
     8 il int read()
     9 {
    10     int x=0,y=1;char c=getchar();
    11     while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
    12     while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    13     return x*y;
    14 }
    15 const int N=1e6+1;
    16 int n,m,ans,a[N*2];
    17 deque<int>q;
    18 int main()
    19 {
    20     n=read();m=n<<1;
    21     go(i,1,n)a[i]=a[n+i]=read();
    22     go(i,2,m)
    23     {
    24         while(q.size()&&i-q.front()>n/2)q.pop_front();
    25         while(q.size()&&a[i-1]-i>a[q.back()]-q.back())q.pop_back();
    26         q.push_back(i-1);
    27         ans=max(ans,a[i]+i+a[q.front()]-q.front());
    28     }
    29     printf("%d
    ",ans);
    30     return 0;
    31 }
    View Code
    光伴随的阴影
  • 相关阅读:
    BZOJ1006: [HNOI2008]神奇的国度
    弦图与区间图
    后缀自动机
    插头DP
    BZOJ3328: PYXFIB
    BZOJ2118: 墨墨的等式
    BZOJ3916: [Baltic2014]friends
    BZOJ1337: 最小圆覆盖
    BZOJ3784: 树上的路径
    代码模版
  • 原文地址:https://www.cnblogs.com/forward777/p/11014754.html
Copyright © 2011-2022 走看看