BZOJ 4709: [Jsoi2011]柠檬
斜率优化,没有细节
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
long long g[1000005],f[1000005],a[1000005],b[1000005],c[1000005],d[1000005],last[1000005];
struct node{
long long k,b;
}line[1000005];
vector<node> vec[1000005];
double check(node a,node b){
double x=((double)b.b-a.b)/(a.k-b.k);
return x;
}
int main(){
int n;
scanf("%d",&n);
for (int i=1; i<=n; i++){
scanf("%lld",&a[i]);
c[i]=c[last[a[i]]]+1;
b[i]=c[i]+1;
d[i]=a[i]*c[i]*2;
last[a[i]]=i;
}
for (int i=1; i<=n; i++){
g[i]=f[i-1]+a[i]*c[i]*c[i];
line[i]=(node){-d[i],g[i]};
int C=a[i];
int tail=(int)vec[C].size()-1;
while (tail>=1 && check(vec[C][tail],vec[C][tail-1])<=check(line[i],vec[C][tail])) vec[C].pop_back(),tail--;
vec[C].push_back(line[i]);
int L=0,R=(int)vec[C].size()-1;
while (L<R){
int mid=(L+R)>>1;
double l,r;
if (mid==0) r=-1ll<<60;
else r=check(vec[C][mid],vec[C][mid-1]);
if (mid==(int)vec[C].size()-1) l= 1ll<<60;
else l=check(vec[C][mid],vec[C][mid+1]);
if (b[i]>=l && b[i]<=r) {
L=mid;
break;
}
if (b[i]>r) R=mid-1;
if (b[i]<l) L=mid+1;
}
f[i]=b[i]*vec[C][L].k+vec[C][L].b+a[i]*b[i]*b[i];
}
printf("%lld\n",f[n]);
return 0;
}

浙公网安备 33010602011771号