类似于斜率优化的东西,果真CF的E以后才会考点算法啊。
感觉这种优化应该很常见,但这题直线只有第一象限的,但是插入,和查找操作是不变的,按极角排序后就可以直接用这个模板了。
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <algorithm> using namespace std; typedef long long ll; struct Line { ll a,b; ll get(ll x) { return a*x+b; } }; struct Convex_Hull { int size; Line ls[200200]; void init() { size=0; } bool is_bad(int one,int two,int three)//目前凸包集为xxx12 要将3插入,判断是否删除2 { Line l1=ls[one],l2=ls[two],l3=ls[three]; return (l2.b-l1.b)*(l1.a-l3.a)>=(l3.b-l1.b)*(l1.a-l2.a);//我这样肯定可以! } void add_line(ll a,ll b) { ls[size++] = Line{a,b};//这样写也可以? while(size>=3 && is_bad(size-3, size-2, size-1) ) { ls[size-2] = ls[size-1]; size--; } } ll query(ll x) { int b=-1,d=size-1; while(d-b > 1) { int mid=(b+d)/2; if( ls[mid].get(x) <= ls[mid+1].get(x) ) { b = mid; } else d = mid; } return ls[d].get(x); } }; #define N 200200 ll sum[N]; ll ans,tans; Convex_Hull cv; int g[N]; int main() { int n; cin>>n; sum[0]=0; for(int i=1;i<=n;i++) { scanf("%d",g+i); sum[i] = sum[i-1]+g[i]; ans += (ll)i*g[i]; } cv.init(); for(int i=2;i<=n;i++) { cv.add_line(i-1, -sum[i-2]); tans = max(tans,cv.query(g[i])+sum[i-1]-(ll)i*g[i]); } //第二遍,逆着写。 cv.init(); for(int i=n-1;i>=1;i--) { cv.add_line(-(i+1), -sum[i+1]); tans = max(tans,cv.query(-g[i])+sum[i]-(ll)i*g[i]); } cout<<ans+tans<<endl; return 0; }