CFR 631 E. Product Sum ( Convex hull trick DP )
Problem - E - Codeforces
pekempeyさんの記事と公式の editorialよりいい解釈はないと思うのでとりあえず。
pekempey.hatenablog.com
Editorial Codeforces Round #344 (Div. 2) - Codeforces
For this problem, we will consider convex hull trick. There are 2 things we will do for each index when traversing, we will update the line of the characteristic of the current index as a usable function, and we will query for the all the usable functions for the maximum f( x ). Since the slope is monotonically increasing, all the popping and pushing lines will be done in the back. Suppose L1 = a1x + b1, L2 = a2x + b2, L3 = a3x + b3 and a1 < a2 < a3, we will not need L2 iff for all x, L2( x ) < L1( x ) OR L2( x ) < L3( x ) satisfies, since it will never be the maximum. Maintaining the usable functions well with this property, we will create a lower convex hull, which will give us opportunity to make fast queries for maximum f( x ). For some x, if the global maximum value in all lines is f_g( x ), f_i( x ) ≤ f_g( x ) ≤ f_j( x ) will satisfy for all i < g and g < j, thus we can apply binary search to find such g.
For how to judge whether L2 is a bad line, we can suppose the intercept of L1 and L3 be ( α, β ), it will be that for all x < α, a1x + b1 > a2x + b2, and for all α < x, a3x + b3 > a2x + b2, carefully moving around the inequality, we will have ( b2 - b3 ) * ( a2 - a1 ) ≤ ( b1 - b2 ) * ( a3 - a2 ).
#include <bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; const int MAXA = 1e6 + 6; typedef long long ll; template <class T> void upmax(T &x, T v){ if( x < v ) x = v; } int n; int a[ MAXN ]; ll pa[ MAXN ]; ll org; // orignal score ll max_delta; // maximum difference after operation struct line{ ll a, b; // ax + b = y line(ll _a = 0, ll _b = 0): a(_a), b(_b){} ll operator() (ll x){ return a * x + b; } }; struct ConvexHull{ deque<line> dq; ConvexHull(){} bool isBad(line f1, line f2, line f3){ return ( f2.b - f3.b ) * ( f2.a - f1.a ) <= ( f1.b - f2.b ) * ( f3.a - f2.a ); } void addLine(line f){ while( dq.size() >= 2 && isBad( dq[ dq.size() - 2 ], dq[ dq.size() - 1 ], f ) ) dq.pop_back(); dq.push_back( f ); } ll qmax(ll x){ int lb = -1, rb = dq.size() - 1; while( lb + 1 < rb ){ int mid = lb + rb >> 1; if( dq[ mid ]( x ) <= dq[ mid + 1 ]( x ) ) lb = mid; else rb = mid; } return dq[ rb ]( x ); } } ch0, ch1; int main(){ ios::sync_with_stdio( false ); cin >> n; for(int i = 1; i <= n; ++i){ cin >> a[ i ]; pa[ i ] = pa[ i - 1 ] + a[ i ]; org += (ll)a[ i ] * i; } for(int i = 2; i <= n; ++i){ ch0.addLine( line( i - 1, -pa[ i - 2 ] ) ); upmax( max_delta, ch0.qmax( a[ i ] ) + pa[ i - 1 ] - (ll)a[ i ] * i ); } for(int i = n - 1; i >= 1; --i){ ch1.addLine( line( -( i + 1 ), -pa[ i + 1 ] ) ); upmax( max_delta, ch1.qmax( -a[ i ] ) + pa[ i ] - (ll)a[ i ] * i ); } cout << org + max_delta << endl; return 0; }
Looks like divide and conquer approach will work as well, in O( n lg n )
Submission #16526854 - Codeforces