zoukankan      html  css  js  c++  java
  • Codeforces 1107G(dp)

    1.答案要取连续的区间疯狂暗示线段树。

    2.外层枚举r,内层枚举l显然过于暴力。

    3.考虑内层的优化。dp[i]:以第i位为结尾的答案(长度大于1的)。dp[i] = max(第一种情况,第二种情况)。解释一下,首先我们可以做到求出i前面gap[j] > gap[i],j < i最大的j的位置pos,然后其中第一种情况为:自力更生,区间pos~i内gap[i]是最大的。这种情况可以使用线段树logn得到区间内最大右子段和;其中第二种情况为:寄人篱下,区间从pos前的某一位一直到i,即最大的gap不是gap[i]。这种直接dp转移,dp[pos] + sum[pos + 1 ~ i]即可。

    4.怎样不暴力枚举巧妙得到pos?这里提供单调栈的方式,每个元素都只进出一次,复杂度完全可以承受。

    5.注意一些细节,比如最大右子段可能只有一位的长度,所以代码中用pos~i-1的右子段加上了第i位的值以保证长度大于1.

    6.为啥非得dp长度大于1的?因为等于1的跟gap没关系了,没法这么搞,且长度为1的……完全可以一开始读入的时候就更新掉。

    7.请结合代码细细体会。

    8.另一种非dp做法:因为答案的maxgap肯定只在n-1个里面选,所以枚举这n-1个gap,然后区间咋选呢,就是:对于这个gap[i],我们可以做到求出两个数组l[i]和r[i],其实和上一个做法很像,l[i]就是gap[i]还能做“土皇帝”向左走得最远的位置,再往左走他就不是最大的了;同理r[i]是向右走的最远。这样只要用线段树查询l[i]到r[i]的最大连续子段和即可。注意有可能i不在这个连续子段和里,但是没关系,这样算出来的值比答案更劣因为减去gap的平方减多了,而我们一会儿就会枚举到真正的答案并更新了。啊对了,l和r数组是在枚举之前用单调栈预处理的,跟dp的那个一样的……网上题解用非dp方法的很多了。

    非dp代码咕咕咕,dp代码主要部分:

     1 const int maxn = 3e5 + 5;
     2 int n;
     3 ll a, d[maxn], c[maxn], dp[maxn], ans;
     4 
     5 class SegmentTree {
     6 public:
     7     #define ls(p)   p << 1
     8     #define rs(p)   p << 1 | 1
     9 
    10     struct Node {
    11         int l, r;
    12         ll rs, sum;
    13     }t[maxn << 2];
    14 
    15     void Push_Up(int p) {
    16         t[p].sum = t[ls(p)].sum + t[rs(p)].sum;
    17         t[p].rs = max(t[rs(p)].rs, t[ls(p)].rs + t[rs(p)].sum);
    18     }
    19 
    20     void Build(int l, int r, int p) {
    21         t[p].l = l, t[p].r = r;
    22         if (l == r) {
    23             t[p].rs = t[p].sum = c[l];
    24             return;
    25         }
    26         int mid = (l + r) >> 1;
    27         Build(l, mid, ls(p));
    28         Build(mid + 1, r, rs(p));
    29         Push_Up(p);
    30     }
    31 
    32     friend Node operator + (const Node x, const Node y) {
    33        return (Node){x.l, y.r, max(y.rs, x.rs + y.sum), x.sum + y.sum};
    34     }
    35     
    36     Node Query(int l, int r, int p) {
    37         if (l <= t[p].l && t[p].r <= r) {
    38             return t[p];
    39         }
    40         int mid = (t[p].l + t[p].r) >> 1;
    41         if (r <= mid)   return Query(l, r, ls(p));
    42         if (mid < l)    return Query(l, r, rs(p));
    43         return Query(l, r, ls(p)) + Query(l, r, rs(p));
    44     }
    45 }T;
    46 
    47 int main() {
    48     read(n), read(a);
    49 
    50     rep(i, 1, n) {
    51         read(d[i]);
    52         read(c[i]);
    53         c[i] = a - c[i];
    54         ans = max(ans, c[i]);
    55     }
    56 
    57     T.Build(1, n, 1);
    58 
    59     rep(i, 1, n)    c[i] += c[i - 1];
    60 
    61     stack<pair<ll, int>> stk;
    62 
    63     rep(i, 2, n) {
    64         int pos;
    65         while (!stk.empty() && stk.top().first < d[i] - d[i - 1]) {
    66             stk.pop();
    67         }
    68         if (stk.empty())    pos = 1;
    69         else    pos = stk.top().second;
    70         stk.push(make_pair(d[i] - d[i - 1], i));
    71 
    72         dp[i] = T.Query(pos, i - 1, 1).rs + c[i] - c[i - 1] - (d[i] - d[i - 1]) * (d[i] - d[i - 1]);
    73         if (pos != 1)   dp[i] = max(dp[i], dp[pos] + c[i] - c[pos]);
    74         ans = max(dp[i], ans);
    75     }
    76 
    77     writeln(ans);
    78     
    79     return 0;
    80 }
  • 相关阅读:
    外设简述
    代C语言上机实践
    css动画效果
    css滑动门原理
    css整理
    html
    html单词
    倒计时.js
    随机方块
    求字符串出现次数和最大值
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10624604.html
Copyright © 2011-2022 走看看