bzoj4709 [jsoi2011]柠檬
Posted ccz181078
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4709 [jsoi2011]柠檬相关的知识,希望对你有一定的参考价值。
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; }
以上是关于bzoj4709 [jsoi2011]柠檬的主要内容,如果未能解决你的问题,请参考以下文章