「Gym102979」Junkyeom's Contest
阿新 • • 發佈:2021-08-27
題目
點這裡看題目。
分析
不難看出,對 \(A\) 排序後,\(P_3,P_4,\dots,P_7\) 在序列上一定是連續的。因此實際上需要列舉的只有 \(P_1,P_2,P_3\) 三個數。
我們需要做下決定:設 \(q=P_4+P_5+P_6+P_7-P_3\),則有 \(P_1<P_2+P_3\) 和 \(P_2<q\) 兩條限制。如果我們列舉 \(P_1\) 或者 \(P_3\),限制會集中在一側,在一側上要選出條件牽連的兩個數來,難度頗大;而如果我們列舉 \(P_2\),這兩條限制分居兩側,從每側選出一個數,簡單不少。因此,我們會選擇列舉 \(P_2\)。
列舉好 \(P_2\)
因此,我們得到了 \(O(n\log n)\) 的演算法。
小結:
- 審慎地決定思考的方向,對於問題的分析不應停留於找出性質、獲得解法 等等,分析也應該可以為你匯出合理的思考方向。
- 注意 \(P_3\) 待選點隱藏的單調性,類似的有「CSP-S2019」劃分
程式碼
#include <bits/stdc++.h> #define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ ) #define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- ) typedef long long LL; const int MAXN = 5e5 + 5; template<typename _T> void read( _T &x )/*{{{*/ { x = 0; char s = getchar(); int f = 1; while( ! ( '0' <= s && s <= '9' ) ) { f = 1; if( s == '-' ) f = -1; s = getchar(); } while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); } x *= f; }/*}}}*/ template<typename _T> void write( _T x )/*{{{*/ { if( x < 0 ) putchar( '-' ), x = -x; if( 9 < x ) write( x / 10 ); putchar( x % 10 + '0' ); }/*}}}*/ int stk[MAXN], top; LL P[MAXN], pre[MAXN], coe[MAXN]; int N; int main() { read( N ); rep( i, 1, N ) read( P[i] ); std :: sort( P + 1, P + 1 + N ); rep( i, 1, N ) pre[i] = pre[i - 1] + P[i]; LL ans = -1; rep( i, 5, N ) { if( top && coe[stk[1]] > P[i] ) { int l = 1, r = top, mid; while( l < r ) { mid = ( l + r + 1 ) >> 1; if( coe[stk[mid]] > P[i] ) l = mid; else r = mid - 1; } int p = std :: lower_bound( P + 1, P + 1 + N, P[stk[l]] + P[i] ) - P - 1; if( i < p && p <= N ) ans = std :: max( ans, coe[stk[l]] + 2 * P[stk[l]] + P[i] + P[p] ); } coe[i] = pre[i - 1] - pre[i - 5] - P[i]; while( top && coe[stk[top]] <= coe[i] ) top --; stk[++ top] = i; } write( ans ), putchar( '\n' ); return 0; }