ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

Flute 很喜欢柠檬。它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬。贝壳一共有 N (1 ≤ N
 ≤ 100,000) 只,按顺序串在树枝上。为了方便,我们从左到右给贝壳编号 1..N。每只贝壳的大小不一定相同,
贝壳 i 的大小为 si(1 ≤ si ≤10,000)。变柠檬的魔法要求,Flute 每次从树枝一端取下一小段连续的贝壳,并
选择一种贝壳的大小 s0。如果 这一小段贝壳中 大小为 s0 的贝壳有 t 只,那么魔法可以把这一小段贝壳变成 s
0t2 只柠檬。Flute 可以取任意多次贝壳,直到树枝上的贝壳被全部取完。各个小段中,Flute 选择的贝壳大小 s
0 可以不同。而最终 Flute 得到的柠檬数,就是所有小段柠檬数的总和。Flute 想知道,它最多能用这一串贝壳
变出多少柠檬。请你帮忙解决这个问题。

Input

第 1 行:一个整数,表示 N。
第 2 .. N + 1 行:每行一个整数,第 i + 1 行表示 si。

Output

仅一个整数,表示 Flute 最多能得到的柠檬数。
对位置i,f[i]表示考虑前i个元素的最多柠檬数
f[0]=1
f[i]=max f[j-1]+a[i]*(j到i之间si出现次数)^2 , 1<=j<=i,si=sj
对每个si分别用单调栈维护斜率优化dp,决策不单调但可以三分求出决策点
#include<cstdio>
#include<vector>
typedef long long i64;
const int R=5000000,N=100007;
char buf[R+3],*ptr=buf-1;
int _(){
    int x=0,c=*++ptr;
    while(c<48)c=*++ptr;
    while(c>47)x=x*10+c-48,c=*++ptr;
    return x;
}
int n,a[N],pv[N],pw[10007],c[N];
i64 f[N];
std::vector<int>q[10007];
void maxs(i64&a,i64 b){if(a<b)a=b;}
i64 p2(i64 x){return x*x;}
double F(int x,int y,int ci,int ai){
    return (f[x-1]-f[y-1]+ai*(p2(c[x])-p2(c[y])))/double(i64(c[x]-c[y])*ai<<1);
}
int main(){
    fread(buf,1,R,stdin);
    n=_();
    for(int i=1;i<=n;++i){
        pv[i]=pw[a[i]=_()];
        c[i]=c[pw[a[i]]]+1;
        pw[a[i]]=i;
    }
    for(int i=1;i<=n;++i){
        int w=a[i],ci=c[i]+1;
        std::vector<int>&Q=q[w];
        while(Q.size()>1&&F(i,Q[Q.size()-1],ci,w)>F(Q[Q.size()-1],Q[Q.size()-2],ci,w))Q.pop_back();
        Q.push_back(i);
        int l=0,r=Q.size()-1;
        while(l+4<=r){
            int m1=l+r>>1,m2=m1+r>>1;
            if(f[Q[m1]-1]+w*p2(ci-c[Q[m1]])<f[Q[m2]-1]+w*p2(ci-c[Q[m2]]))l=m1;
            else r=m2;
        }
        for(int p=l;p<=r;++p)maxs(f[i],f[Q[p]-1]+w*p2(ci-c[Q[p]]));
    }
    printf("%lld",f[n]);
    return 0;
}

 

 
posted on 2016-10-18 12:19  nul  阅读(342)  评论(0编辑  收藏  举报