Codeforces edu round11 F(斜率DP)

2016-04-26 19:55:10

传送门

题意:给出 n 个数,有正有负,让你求出一个连续字段 [l,r],使得 Sigma((i - l + 1) * a[i]), l<=i<=r 的值最大

思路:设 Si = a1+a2+...ai,Qi = 1*a1+2*a2+...+i*ai,那么 [l,r] 的答案就是 Qr - Ql-1 - (l - 1) * (Sr - Sl-1)。

  设 G = Qr - Ql-1 - (l - 1) * (Sr - Sl-1)

         = Qr - (l-1) * Sr - Ql-1 + (l-1) * Sl-1

  令 y = -Ql-1 + (l-1) * Sl-1 ,x = l-1

  则 G = Qr - x * Sr + y

  即 y = x * Sr - Qr + G

  那么我们枚举 r ,对于每个 r 找到一个 l 使得 G 最大,那么也就是对于斜率为 Sr 且过(x,y)的直线在 y 轴上的截距最大。

  考虑 r 时,1~r-1 可以看成二维坐标上的一些点,那么我们维护一个上凸的凸壳,那么把斜率为 Sr 的直线从上方降下来,与直线相交的第一个点就是答案了,由于我们维护的是凸壳,所以从凸壳左边到右边,答案是先递增后递减的,因此可以在凸壳上三分 / 二分,就能得到答案了,凸壳可以用类似凸包的方法来维护。

  Notice:注意整数三分的细节。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <time.h>
 5 #include <math.h>
 6 #include <vector>
 7 #include <map>
 8 #include <set>
 9 #include <stack>
10 #include <queue>
11 #include <string>
12 #include <iostream>
13 #include <algorithm>
14 using namespace std;
15 
16 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
17 #define MEM(a,b) memset(a,b,sizeof(a))
18 #define MP(a,b) make_pair(a,b)
19 #define PB push_back
20 #define X first
21 #define Y second
22 
23 typedef long long ll;
24 typedef pair<ll,ll> pll;
25 const double eps = 1e-8;
26 const int INF = (1 << 30) - 1;
27 const int MAXN = 200010;
28 
29 int n,sz;
30 ll ans,S[MAXN],Q[MAXN];
31 pll sta[MAXN];
32 
33 ll Gety(int p){
34     return -Q[p - 1] + 1ll * (p - 1) * S[p - 1];
35 }
36 
37 void Insert(ll x,ll y){
38     while(sz >= 2){
39         ll cur = (y - sta[sz].Y) * (sta[sz].X - sta[sz - 1].X)
40                 - (sta[sz].Y - sta[sz - 1].Y) * (x - sta[sz].X);
41         if(cur >= 0) sz--;
42         else break;
43     }
44     sta[++sz] = MP(x,y);
45 }
46 
47 ll Cal(int v,ll k){
48     return sta[v].Y - k * sta[v].X;
49 }
50 
51 ll Solve(ll k){
52     int l = 1,r = sz;
53     while(l < r - 1){
54         int mid1 = getmid(l,r);
55         int mid2 = getmid(mid1,r);
56         if(mid1 == mid2) break;
57         ll res1 = Cal(mid1,k);
58         ll res2 = Cal(mid2,k);
59         if(res1 > res2) r = mid2;
60         else l = mid1;
61     }
62     ll res = 0;
63     for(int i = l; i <= r; ++i) res = max(res,Cal(i,k));
64     return res;
65 }
66 
67 int main(){
68     scanf("%d",&n);
69     for(int i = 1; i <= n; ++i){
70         int a;
71         scanf("%d",&a);    
72         ans = max(ans,(ll)a);
73         S[i] = S[i - 1] + a;
74         Q[i] = Q[i - 1] + 1ll * i * a;
75     }
76     Insert(0,Gety(1));
77     for(int i = 2; i <= n; ++i){
78         ll res = Solve(S[i]) + Q[i];
79         ans = max(ans,res);
80         Insert(i - 1,Gety(i));
81     }
82     printf("%lld\n",ans);
83     return 0;
84 }

 

posted @ 2016-04-26 20:08  Naturain  阅读(263)  评论(0编辑  收藏  举报