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 }
原文地址:https://www.cnblogs.com/AlphaWA/p/10624604.html