zoukankan      html  css  js  c++  java
  • BZOJ2216 Poi2011 Lightning Conductor 【决策单调性优化DP】

    Description

    已知一个长度为n的序列a1,a2,...,an。
    对于每个1<=i<=n,找到最小的非负整数p满足 对于任意的j, aj < = ai + p - sqrt(abs(i-j))

    Input

    第一行n,(1<=n<=500000)
    下面每行一个整数,其中第i行是ai。(0<=ai<=1000000000)

    Output

    n行,第i行表示对于i,得到的p

    Sample Input

    6
    5
    3
    2
    4
    2
    4

    Sample Output

    2
    3
    5
    3
    5
    4


    决策单调性优化DP
    。。。调了一晚上,都要自闭了


    首先可以发现根号函数是一个增长越来越慢的函数
    所以一个点如果不能对答案造成贡献,那么他永远都不能造成贡献了
    然后就考虑怎么维护这个东西
    首先正反跑两遍然后取max这个思路非常显然
    现在可以考虑怎么维护单次的贡献
    因为对于i,需要最大化
    (h_j - h_i + sqrt(i-j))
    所以我们可以把原序列划分成一些区间
    使得这些区间可以取到最大值
    然后每次统计贡献直接在区间上查找就可以了
    考虑维护一个队列来维护([i,n])这个区间的所有最优区间
    每个节点用三元组([l,r,pos])表示
    代表在([l,r])这个区间里面pos可以贡献最大值
    然后直接每次看一看如果当前新加入的节点是可以完全包含末尾区间,直接弹出,知道不能操作
    这时如果序列为空直接加入([i,n,i])
    否则把最后一个区间划分成两个区间进行操作就可以了


    注意统计贡献的时候参数顺序很重要


    //Author: dream_maker
    #include<bits/stdc++.h>
    using namespace std;
    //----------------------------------------------
    //typename
    typedef long long ll;
    //convenient for
    #define for_up(a, b, c) for (int a = b; a <= c; ++a)
    #define for_down(a, b, c) for (int a = b; a >= c; --a)
    #define for_vector(a, b) for (int a = 0; a < (signed)b.size(); ++a)
    //inf of different typename
    const int INF_of_int = 1e9;
    const ll INF_of_ll = 1e18;
    //fast read and write
    template <typename T>
    void Read(T &x) {
      bool w = 1;x = 0;
      char c = getchar();
      while (!isdigit(c) && c != '-')c = getchar();
      if (c == '-')w = 0, c = getchar();
      while (isdigit(c)) {
        x = (x<<1) + (x<<3) + c -'0';
        c = getchar();
      }
      if (!w) x = -x;
    }
    template <typename T>
    void Write(T x) {
      if (x < 0) {
        putchar('-');
        x = -x; 
      }
      if (x > 9)Write(x / 10);
      putchar(x % 10 + '0');
    }
    //----------------------------------------------
    const int N = 500010;
    const double eps = 1e-5;
    int n, l, r;
    int dp[N] = {0}, h[N];
    struct Node {
      int l, r, pos;
      Node(){}
      Node(int l, int r, int pos):l(l), r(r), pos(pos){}
    }p[N];
    double cal(int a, int b) { // 一定注意顺序 是统计 a覆盖b的最小高度
      return (double)h[b] + sqrt(abs(a - b)) - (double)h[a];
    }
    int find(Node t, int x) {
      int l = t.l, r = t.r, ans = 0;
      while (l <= r) {
        int mid = (l + r) >> 1;
        if(cal(mid, t.pos) <= cal(mid, x)) r = mid - 1, ans = mid;
        else l = mid + 1;
      }
      return ans;
    }
    void solve(bool typ) {
      int l = 1, r = 0;
      for_up(i, 1, n) {
        if (l <= r && ++p[l].l > p[l].r) ++l;
        if (l > r || cal(n, i) > cal(n, p[r].pos)) {
          // p[r] 无论如何不会比i优 直接弹掉
          while (l <= r && cal(p[r].l, p[r].pos) < cal(p[r].l, i)) --r;
          int now = (l > r) ? i : find(p[r], i);
          if (l <= r) p[r].r = now - 1;// 如果上一个区间存在 更新右端点
          p[++r] = (Node){now, n, i};
        }
        int id = typ ? n - i + 1 : i;
        dp[id] = max(dp[id], (int)ceil(cal(i, p[l].pos)));
      }
    }
    int main() {
      Read(n);
      for_up(i, 1, n) Read(h[i]);
      solve(0);
      reverse(h + 1, h + n + 1);
      solve(1);
      for_up(i, 1, n) {
        Write(dp[i]);
        putchar('
    ');
      }
      return 0;
    }
    
  • 相关阅读:
    制作ubuntu容器完整步骤
    linux系统python3安装pip
    ssh连接服务器提示拒绝了密码
    ubuntu中vi编辑中按键错误
    虚拟机ubuntu连不上网
    NOIP2020退役记
    【NOIp2020游记】
    loki简单安装配置使用
    .net下com调用支持x86/x64
    nginx 504 Gateway Time-out
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9727010.html
Copyright © 2011-2022 走看看