P5504 [JSOI2011] 柠檬 题解
首先容易想到记 \(f_i\) 表示前 \(i\) 个位置能得到的最大价值,枚举以 \(i\) 结尾的段直接 dp。
发现最后一个段选的颜色必定为 \(s_i\),不然可以令 \([i,i]\) 为单独一段。且以 \(i\) 结尾的段开头颜色也一定是 \(s_i\)。记 \(c_i\) 表示 \([1,i]\) 中与 \(i\) 颜色相同的位置个数,有:
\[f_i=\max_{1\le j\le i\land s_j=s_i} f_{j-1}+s_i(c_i-c_j+1)^2
\]
然后就是斜率优化板子题,时间复杂度 \(\mathcal O(n)\)。
参考代码:
#include<bits/stdc++.h>
#define ll long long
#define mxn 100003
#define pb push_back
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;
int n,a[mxn],p[mxn],c[10003];
ll f[mxn],g[mxn];
vector<int>q[10003];
inline ll get(int x,int y){
return g[x]+((ll)p[y]*p[y]-2ll*(p[x]-1)*p[y])*a[x];
}
signed main(){
scanf("%d",&n);
rep(i,1,n)scanf("%d",&a[i]),p[i]=++c[a[i]];
rep(i,1,n){
g[i]=f[i-1]+(p[i]-1)*(p[i]-1ll)*a[i];
while(q[a[i]].size()>1&&(g[q[a[i]][q[a[i]].size()-1]]-g[q[a[i]][q[a[i]].size()-2]])*(p[i]-p[q[a[i]][q[a[i]].size()-1]])<=
(g[i]-g[q[a[i]][q[a[i]].size()-1]])*(p[q[a[i]][q[a[i]].size()-1]]-p[q[a[i]][q[a[i]].size()-2]]))q[a[i]].pop_back();
q[a[i]].pb(i);
while(q[a[i]].size()>1&&get(q[a[i]][q[a[i]].size()-1],i)<=get(q[a[i]][q[a[i]].size()-2],i))q[a[i]].pop_back();
f[i]=get(q[a[i]].back(),i);
}
cout<<f[n];
return 0;
}

浙公网安备 33010602011771号