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;
}
posted @ 2025-07-05 17:07  zifanwang  阅读(12)  评论(0)    收藏  举报