bzoj 4709 [Jsoi2011]柠檬

网友投稿 749 2022-08-29

bzoj 4709 [Jsoi2011]柠檬

bzoj 4709 [Jsoi2011]柠檬

​​ 动态规划+单调栈的思想

斜率优化那个i实在没看懂

先附上neither_nor的题解.

考虑DP,f[i]表示前i个的最大价值.

那么在最后一段所选的颜色一定是i的情况下,最后一段的开头的颜色也一定是i的颜色,否则开头一段也没有贡献,不然单分出去一段.

我们发现对于任意一个i,他所选的最后一段所指定的颜色一定是i的颜色,因为否则的话i这个点就会没有贡献,一定不如最后一段只选一个i.

那么对于f[i],假设之前存在一个点j,这个点的颜色a[j]与i的颜色a[i]相等,那么我们可以让f[i]由j转移,价值为f[j-1]+a[j]*(s[i]-s[j]+1)^2,s[i]代表前i个数里a[i]出现的次数

我们发现对于任意一个颜色x,随着这个颜色的数不断出现,由每一个之前的a[j]=x的j转移所产生的价值都会不断增加,且j越小,增加的越块,如果有j1< j2,并且j1当前的价值比j2大了,那么j2就没有用了,于是我们可以维护一个单调栈,每次如果栈顶第二个的元素超过了栈顶,就把栈顶弹出,决策的时候直接用栈顶决策

而我们发现可能会出现栈顶第三个元素超过了栈顶,而栈顶第二个元素还没超过栈顶的情况,我们需要避免这种情况。我们发现对于任意的j1< j2< i1< i2,如果j1超过i1的时间比j2超过i1的时间要早,那么j1超过i2的时间也一定比j2超过i2的时间早,证明显然,并且我们对于任意的(j1,j2),j1< j2,我们都能直接算出在第几个颜色与j1,j2相等的数出现的时候,j1会超过j2,那么在我们即将把i压入栈顶的时候,只要当前栈顶第二个元素超过i的时间比当前栈顶超过i的时间要早,那么栈顶就也没用了,我们就可以弹栈,这样的话栈里的每一个元素超过上一个元素的时间也是单调的,于是就没有问题了.

注意到 我们需要避免每个元素超过上一个的时间不是单调

设分别为j1,j2如果 j2超过j1相比j1超过i要早说明j1一定弹掉

另一位大爷对最后一段的理解是:

因为我们要避免每一个元素超过上一个元素的时间也是单调的, 那么设栈里第二个元素为j2, 栈顶即第一个元素为j1, 即将加入栈的为i, 那么当j2超过j1的时候比j1超过i的时候早,那么我们弹栈. 先考虑为什么这么做, 首先这样能弹栈说明了j1一定不优. 证明: 由于本身i这个地方可以自成一段,也就是说i是可以用i点这个决策的, 那么当j1比i优的时候, j1不应该弹栈,否则肯定弹栈.

但又因为j1如果比i优的话, 当j1比i优的时候, j2已经比j1优了(这是弹栈条件), 所以j1还是要被弹栈. 所以满足这个条件弹栈肯定是没有问题的. 接下来我们再看为什么这样就能保证每一个元素超过上一个元素的时间也是单调的,因为我们通过弹栈保证了, j2比j1优的时间一定 比 j1比i优的时间晚(否则j1就被弹出去了), 那么因为我们一直这样保证, 所以当i已经不再是栈顶元素是, 因为j2比j1优的时间一定比j1比i优的时间晚, 那么设压在i之上的元素是p, 我们也保证了j1比i优的时间晚肯定比 i比p优的时间晚(否则我们要弹栈, 现在讨论的是一个合法的即真正单调的单调栈). 这样递推下去,栈中一层比一层晚, 所以就不会出现栈顶第三个元素超过了栈顶,而栈顶第二个元素还没超过栈顶的情况.

#include#define ll long longusing namespace std;inline char gc(){ static char now[1<<16],*S,*T; if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;} return *S++;}inline int read(){ int x=0,f=1;char ch=gc(); while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();} while(isdigit(ch)) x=x*10+ch-'0',ch=gc(); return x*f;}const int N=100005;vector q[N>>3];int a[N],c[N>>3],s[N],n;ll dp[N];inline ll gao(int x,int v){ return dp[x-1]+(ll)a[x]*v*v;}inline int calc(int x,int y){ int l=1,r=n,res=n+1; while(l<=r){ int mid=l+r>>1; if (gao(x,mid-s[x]+1)>=gao(y,mid-s[y]+1)) res=mid,r=mid-1;else l=mid+1; }return res;}int main(){ freopen("bzoj4709.in","r",stdin); n=read(); for (int i=1;i<=n;++i){ //printf("%d\n",i); int x=read(),size;a[i]=x;++c[x];s[i]=c[x];size=q[x].size(); while(size>=2&&calc(q[x][size-2],q[x][size-1])<=calc(q[x][size-1],i)) q[x].pop_back(),size=q[x].size(); q[x].push_back(i);size=q[x].size(); while(size>=2&&calc(q[x][size-2],q[x][size-1])<=s[i]) q[x].pop_back(),size=q[x].size(); int j=q[x].back();dp[i]=gao(j,s[i]-s[j]+1); }printf("%lld\n",dp[n]); return 0;}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:codeforces 453E Little Pony and Lord Tirek
下一篇:关于mysql的优化一些点(mysql优化常用的几种方法)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~