Luogu P5504 [JSOI2011] 柠檬

题链

分析

发现每段头和尾一定相同
所以可以DP
\(s[i]\)表示前\(i\)个与\(a[i]\)相同的个数,\(f[i]\)为答案

\[f[i]=f[j-1]+a[i]\times (s[i]-s[j]+1)^2 \]

有i,j,可以斜率优化,用\(Vector\)维护凸包

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int N=1e5+5,M=1e4+5;;
int n,a[N],s[N],lst[M];
ll f[N];
vector<int>V[M];

inline ll Y(int x) {
	return f[x-1]+(ll)a[x]*s[x]*s[x]-2*a[x]*s[x];
}
inline int X(int x) {
	return s[x];
}
inline void clear(vector<int> &x,int i) {
	int t=x.size();
	while(t>1&&(Y(x[t-1])-Y(x[t-2]))*(X(i)-X(x[t-1]))<=(Y(i)-Y(x[t-1]))*(X(x[t-1])-X(x[t-2]))) x.pop_back(),t--;
}
inline void del(vector<int> &x,int i) {
	int t=x.size();
	while(t>1&&(Y(x[t-1])-Y(x[t-2]))<=(ll)i*(X(x[t-1])-X(x[t-2]))) x.pop_back(),t--;
}
int main() {
//	freopen("1.in","r",stdin);
//	freopen("1.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n;i++) {
		s[i]=s[lst[a[i]]]+1;
		lst[a[i]]=i;	
	}
	for(int i=1;i<=n;i++) {
		clear(V[a[i]],i);
		V[a[i]].push_back(i);
		del(V[a[i]],2*a[i]*s[i]);
		auto t=V[a[i]].end(); t--;
		f[i]=f[(*t)-1]+(ll)a[i]*(s[i]-s[*t]+1)*(s[i]-s[*t]+1);
	}
	printf("%lld\n",f[n]);
	return 0;
}
posted @ 2021-02-25 11:44  wwwsfff  阅读(58)  评论(0)    收藏  举报