A very obvious \ (nk\) DP state \ (f[i][k]\) represents the maximum cost that can be obtained when \ (I\) is the last element of the section \ (k\). When transferring, enumerate the last element of the previous paragraph \ (j\) update status. Consider how to optimize this process? The main time is consumed in two parts: one is to determine the contribution of an interval, and the other is to find the maximum value.
Both of these can be maintained using line-segment trees, and the contribution of a section can be scanned, while the maximum value is maintained by the direct segment tree. How to scroll seems to be the hardest ... Think for a while, because obviously memset unacceptable, but we can \ (O (n) \) Build Ah ... I have no words for my own ZZ ~
#include <bits/stdc++.h>using namespacestd;#defineMAXN 2000000#defineMAXM 40000intN, K, ans, a[maxn], REC[MAXN], LAST[MAXN];intf[maxm][ -];intRead () {intx =0, k =1; CharC c =GetChar (); while(C <'0'|| C >'9') {if(c = ='-') K =-1; c =GetChar ();} while(c >='0'&& C <='9') x = x *Ten+ C-'0', C =GetChar (); returnX *K;}structsegament_tree{intMX[MAXN], MARK[MAXN]; voidPush_down (intp) {mark[p<<1] + = Mark[p], mark[p <<1|1] +=Mark[p]; Mx[p<<1] + = Mark[p], mx[p <<1|1] +=Mark[p]; MARK[P]=0; } voidBuild (intPintLintRintK) {if(L = = r) {Mark[p] =0, mx[p] = f[l-1][K];return; } intMid = (L + r) >>1; MARK[P]=0; Build (P<<1, L, Mid, K), Build (P <<1|1, Mid +1, R, K); MX[P]= Max (Mx[p <<1], Mx[p <<1|1]); } voidUpdate (intPintLintRintLintRintx) {if(l <= L && R >= R) {Mx[p] + = x, mark[p] + = x;return; } if(L > R | | R < L)return; intMid = (L + r) >>1; Push_down (P); Update (P<<1, L, Mid, L, R, X); Update (P<<1|1, Mid +1, R, L, R, X); MX[P]= Max (Mx[p <<1], Mx[p <<1|1]); } intQuery (intPintLintRintLintR) {if(l <= L && R >= R) {returnmx[p];} if(L > R | | R < L)return 0; intMid = (L + r) >>1; Push_down (P); returnMax (Query (P <<1, L, Mid, L, R), Query (P <<1|1, Mid +1, R, L, R)); }}t[2];intMain () {n= Read (), K =read (); for(inti =1; I <= N; i + +) {A[i]=read (); Last[i]= Rec[a[i]] [rec[a[i]] =i; } intnow =1, pre =0; for(intj =1; J <= K; J + +) { for(inti =1; I <= N; i + +) {T[pre]. Update (1,1, N, Last[i] +1I1); F[I][J]= T[pre]. Query (1,1N1, i); } T[now]. Build (1,1, N, j); Swap (now, pre); } printf ("%d\n", F[n][k]); return 0;}
"Cf#426" (Div. 1) b.the Bakery