题目
首先我们容易想到,每一个连续段两端的颜色一定相同。
预处理出(sum_i)表示(1sim i)中颜色为(a_i)的贝壳的个数。
设(f_i)为前(i)个贝壳的最大答案。
那么容易写出转移方程(f_i=maxlimits_{jin[1,i]wedge a_i=a_j}(f_{j-1}+a_i(sum_i-sum_j+1)^2))
这个东西显然可以斜率优化,每种颜色维护一个凸包即可。
可以拆成这样
(f_i=a_i(sum_i+1)^2+maxlimits_{jin[1,i]wedge a_i=a_j}((-2sum_i)(a_jsum_j)+(f_{j-1}+a_jsum_j^2-2a_jsum_j)))
#include<bits/stdc++.h>
#define ll long long
#define ld long double
#define pub push_back
#define pob pop_back
#define t1 s[id][s[id].size()-1]
#define t2 s[id][s[id].size()-2]
using namespace std;
const int N=100007,M=10007;const ld eps=1e-8;
int a[N],sum[N],pos[N];vector<int>s[N];ll x[N],y[N],f[N];
int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
ld slope(int i,int j){return (ld)(y[j]-y[i])/(x[j]-x[i]);}
ll sqr(int x){return 1ll*x*x;}
int main()
{
int n=read(),i,id;
for(i=1;i<=n;++i) a[i]=read(),sum[i]=sum[pos[a[i]]]+1,pos[a[i]]=i;
for(i=1;i<=n;++i) x[i]=1ll*sum[i]*a[i];
for(i=1;i<=n;++i)
{
id=a[i],y[i]=f[i-1]+1ll*a[i]*sum[i]*(sum[i]-2);
while(s[id].size()>=2&&slope(t2,t1)<=slope(t2,i)+eps) s[id].pob();
s[id].pub(i);
while(s[id].size()>=2&&slope(t2,t1)<=2.0*sum[i]+eps) s[id].pob();
f[i]=f[t1-1]+a[i]*sqr(sum[i]-sum[t1]+1);
}
return !printf("%lld",f[n]);
}