[小A与最大子段和][斜率优化dp+二分]

链接:https://ac.nowcoder.com/acm/contest/545/A
来源:牛客网
题目描述

小A在网上看到了 "最大子段和" 问题的解法.第二天,小A向小B讲解了这个问题.
但小B抛出了一个疑问:如果让每个数的权值是它本身的值乘上它在子段中的位置呢?
小A被难住了,你能帮他解决这个问题吗?
形式化地说,你需要在一个序列 a  里找到一个非空子段(子段是连续的) b, 满足 mi=1b[i]×i∑i=1mb[i]×i 最大( m 是 b 的长度)
输入描述:
第一行一个整数 n ,表示序列的长度
第二行 n 个整数,第 i 个数表示 aiai
输出描述:
一行一个整数,表示最大的 mi=1b[i]×i∑i=1mb[i]×i 
示例1
输入
4
-100 1 2 3
输出

14

说明
1×1+2×2+3×3=141×1+2×2+3×3=14

备注:
1n2×10^5
0ai|2×10^3

题解:枚举每个区间右端点,如果再枚举左端点则复杂度为O(N^2)不可行。使用斜率优化。

令s为前缀和,p[i] = ∑(i * s[i]),区间[j, i]以i为右端点时区间和可以表示为p[i] - p[j - 1] - (j - 1) * (s[i] - s[j - 1])。

斜率方程(k < j < i) j比k优,((j * s[j] - p[j]) - (k * s[k] - p[k])) / (j - k) > s[i],由于前缀和s不单调所以不能直接将队首节点弹出,(即只通过插入当前点更新队尾元素,不能丢弃队首元素,【而如果前缀和s单调,易知队首元素在当前不满足时也不会满足以后的点即可以丢弃】)
所以就不能通过丢弃队首来找满足条件的点了,只能通过二分斜率凸包来找满足条件的斜率。
 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstdio>
 6 #include<queue>
 7 #include<time.h>
 8 using namespace std;
 9 typedef long long ll;
10 const int N = 2e5+10;
11 ll a[N],A[N],B[N],dp[N];
12 struct pot{
13     int x;
14     ll y;
15 }que[N];
16 int head=1;
17 int tail=0;
18 bool check(int s,int k){
19     if(tail<2)return true;
20     return que[s].y-que[s-1].y<(que[s].x-que[s-1].x)*B[k];
21 }
22 int main(){
23     int n;
24     scanf("%d",&n);
25     for(int i=1;i<=n;i++){scanf("%lld",&a[i]);dp[i]=a[i];}
26     for(int i=1;i<=n;i++){
27         A[i]=i*a[i]+A[i-1];
28         B[i]=a[i]+B[i-1];
29     }
30     ll ans=-10000000;
31     for(int i=1;i<=n;i++){
32         int l=head;
33         int r=tail;
34         int m=l;
35         while(l<=r){
36             int mid=(l+r)/2;
37             if(check(mid,i)){
38                 m=mid;
39                 r=mid-1;
40             }
41             else l=mid+1;
42         }
43         dp[i]=max(A[i]-A[que[m-1].x]-que[m-1].x*(B[i]-B[que[m-1].x]),dp[i]);
44         ans=max(ans,dp[i]);
45         while(tail>=2&&(i*B[i]-A[i]-(que[tail].y))*(que[tail].x-que[tail-1].x)>(i-que[tail].x)*((que[tail].y-que[tail-1].y)))tail--;
46         que[++tail].x=i;
47         que[tail].y=i*B[i]-A[i];
48     }
49     cout<<ans<<endl;
50     return 0;
51 }
View Code

 

 
 

 

posted @ 2019-03-30 11:34  MekakuCityActor  阅读(363)  评论(0编辑  收藏  举报