1 条题解

  • 0
    @ 2025-8-24 22:57:54

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar FFTotoro
    龙猫

    搬运于2025-08-24 22:57:54,当前版本为作者最后更新于2024-05-12 21:50:03,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    观察性质题。下称“投喂 AA 饲料”为“执行 AA 操作”,BB 饲料同理。

    考虑暴力怎么做。显然一个 AA 操作等价于令某个 CiCiDC_i\leftarrow C_i-D,而最后能通过 BB 操作完成的序列 CC 必然单调不降(因为每次可以给一个后缀 +1+1,所以前面的数永远不会大于后面的)。

    考虑另一种“暴力”,就是将询问离线,按 RR 从小到大排序然后扫一遍过去,每次扫到一个新的 RR,如果 CR1>CRC_{R-1}>C_R 就暴力往前更新,直到满足条件。

    上面的这种暴力看起来很能找性质进行优化。观察到如果我们更新过了一对相邻的数,那么接下来不管怎么更新,它们的差不变!证明:每次更新都是对一个 CiC_i 进行 D-D,考虑 modD\bmod D 的剩余系即可。于是考虑用一个栈维护还没有更新的位置(因为如果右边的不用更新左边的也不用更新),所以每次从栈顶开始暴力往下查有没有冲突,如果有直接更新中间一段的值,然后把栈顶删掉……均摊一下这种操作最多做 NN 次。区间加区间和可以用线段树维护。于是做完了,时间复杂度 O(NlogN)O(N\log N)

    放代码:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    typedef pair<int,int> pii;
    inline int ceil_div(int x,int y){
      return x/y+!!(x%y);
    }
    class segtree{
      private:
        int n;
        vector<pii> B;
        vector<int> S,T;
      public:
        inline void pushup(int u){
          S[u]=S[u<<1]+S[u<<1|1];
        }
        inline int size(int u){
          return B[u].second-B[u].first+1;
        }
        inline void pushdown(int u){
          S[u<<1]+=T[u]*size(u<<1),S[u<<1|1]+=T[u]*size(u<<1|1);
          T[u<<1]+=T[u],T[u<<1|1]+=T[u],T[u]=0;
        }
        segtree(int N){
          n=N,B.resize(n<<2),S.resize(n<<2),T.resize(N<<2);
          function<void(int,int,int)> build=[&](int u,int l,int r){
            if(B[u]=make_pair(l,r);l==r)return;
            int m=l+r>>1;
            build(u<<1,l,m),build(u<<1|1,m+1,r);
          };
          build(1,0,n-1);
        }
        inline void update(int u,int l,int r,int x){
          if(B[u].first>r||B[u].second<l)return;
          if(l<=B[u].first&&B[u].second<=r){
            T[u]+=x,S[u]+=x*size(u); return;
          }
          pushdown(u);
          update(u<<1,l,r,x),update(u<<1|1,l,r,x);
          pushup(u);
        }
        inline int query(int u,int l,int r){
          if(B[u].first>r||B[u].second<l)return 0;
          if(l<=B[u].first&&B[u].second<=r)return S[u];
          pushdown(u);
          return query(u<<1,l,r)+query(u<<1|1,l,r);
        }
    }; // 线段树
    main(){
      ios::sync_with_stdio(false);
      int n,d; cin>>n>>d;
      vector<int> c(n);
      for(auto &i:c)cin>>i;
      int q; cin>>q;
      vector<vector<pii> > Q(n);
      vector<int> R(q);
      for(int i=0;i<q;i++){
        int l,r; cin>>l>>r;
        Q[r-1].emplace_back(l-1,i);
      } // 把询问离线下来
      segtree t(n);
      auto get=[&](int p){return c[p]-t.query(1,p,p)*d;};
      stack<int> s;
      for(int i=0;i<n;i++){
        int r=i;
        while(!s.empty()){
          int l=s.top(),x=get(r-1),y=get(r);
          if(x<=y)break;
          t.update(1,l,r-1,ceil_div(x-y,d));
          r=l,s.pop();
        } // 弹栈顶,均摊 N 次
        s.emplace(r);
        for(auto [l,w]:Q[i])
          R[w]=(get(l)<0?-1:t.query(1,l,i));
      }
      for(int i:R)cout<<i<<'\n';
      return 0;
    }
    
    • 1

    信息

    ID
    10239
    时间
    2000ms
    内存
    1024MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者