【BZOJ4709】[Jsoi2011]柠檬

Description

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

Input

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

Output

仅一个整数,表示 Flute 最多能得到的柠檬数。

Sample Input

5
2
2
5
2
3

Sample Output

21
//Flute 先从左端取下 4 只贝壳,它们的大小为 2, 2, 5, 2。选择 s0 = 2,那么这一段里有 3 只大小为 s0 的贝壳,通过魔法可以得到 2×3^2 = 18 只柠檬。再从右端取下最后一只贝壳,通过魔法可以得到 1×3^1 = 3 只柠檬。总共可以得到 18 + 3 = 21 只柠檬。没有比这更优的方案了。

题解:大爷说他从来没做过用单调栈优化的斜率优化,唯一的一道还是他自己出的,不过今天我也算是见过第一道这样的题了。

首先,从两边进行操作可以看成只从一边进行操作,然后我们将原序列反过来再做一遍就行了。

其次,每次施魔法时,区间的左端点和右端点一定都是相同种类的贝壳,这告诉我们应该将每种颜色放到一起处理。然后可以列出DP方程:

$f[i]=max{f[j-1]+(s[i]-s[j]+1)^2*color}$。

其中s[i]表示i这个颜色的前缀和,然后移项

$f[j-1]+(s[j]-1)^2*color=2*s[i]*color*(s[j]-1)+f[i]-s[i]*v[i]$

发现x单调递增,y单调递增,k也单调递增,求的还是上凸包!所以用对于每个颜色都用一个单调栈维护即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define y(_) (f[(_)-1]+(s[_]-1)*(s[_]-1)*j)
#define x(_) (s[_]-1)
#define k (2*s[i]*j)
using namespace std;
const int maxn=100010;
typedef long long ll;
int n,m;
ll ans;
int t[maxn],last[maxn],pre[maxn];
ll v[maxn],s[maxn],f[maxn],g[maxn];
vector<int> st[maxn];
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int main()
{
n=rd();
int i,j;
for(i=1;i<=n;i++) v[i]=rd(),pre[i]=last[v[i]],last[v[i]]=i,s[i]=s[pre[i]]+1,m=max(m,(int)v[i]);
for(i=1;i<=m;i++) t[i]=-1;
for(i=1;i<=n;i++)
{
j=v[i];
while(t[j]>0&&(y(i)-y(st[j][t[j]]))*(x(st[j][t[j]])-x(st[j][t[j]-1]))>=(y(st[j][t[j]])-y(st[j][t[j]-1]))*(x(i)-x(st[j][t[j]]))) t[j]--,st[j].erase(st[j].end()-1);
t[j]++,st[j].push_back(i);
while(t[j]>0&&(y(st[j][t[j]])-y(st[j][t[j]-1]))<=k*(x(st[j][t[j]])-x(st[j][t[j]-1]))) t[j]--,st[j].erase(st[j].end()-1);
g[i]=f[i]=f[st[j][t[j]]-1]+(s[i]-s[st[j][t[j]]]+1)*(s[i]-s[st[j][t[j]]]+1)*j;
}
for(i=1;(i<<1)<=n;i++) swap(v[i],v[n-i+1]);
memset(last,0,sizeof(last));
for(i=1;i<=n;i++) pre[i]=last[v[i]],last[v[i]]=i,s[i]=s[pre[i]]+1;
for(i=1;i<=m;i++) st[i].clear(),t[i]=-1;
for(i=1;i<=n;i++)
{
j=v[i];
while(t[j]>0&&(y(i)-y(st[j][t[j]]))*(x(st[j][t[j]])-x(st[j][t[j]-1]))>=(y(st[j][t[j]])-y(st[j][t[j]-1]))*(x(i)-x(st[j][t[j]]))) t[j]--,st[j].erase(st[j].end()-1);
t[j]++,st[j].push_back(i);
while(t[j]>0&&(y(st[j][t[j]])-y(st[j][t[j]-1]))<=k*(x(st[j][t[j]])-x(st[j][t[j]-1]))) t[j]--,st[j].erase(st[j].end()-1);
f[i]=f[st[j][t[j]]-1]+(s[i]-s[st[j][t[j]]]+1)*(s[i]-s[st[j][t[j]]]+1)*j;
}
ans=0;
for(i=0;i<=n;i++) ans=max(ans,g[i]+f[n-i]);
printf("%lld",ans);
return 0;
}

【BZOJ4709】[Jsoi2011]柠檬 斜率优化+单调栈的更多相关文章

  1. bzoj4709: [Jsoi2011]柠檬 斜率优化

    题目链接 bzoj4709: [Jsoi2011]柠檬 题解 斜率优化 设 \(f[i]\) 表示前 \(i\)个数分成若干段的最大总价值. 对于分成的每一段,左端点的数.右端点的数.选择的数一定是相 ...

  2. [BZOJ4709][JSOI2011]柠檬(斜率优化DP)

    显然选出的每一段首尾都是相同的,于是直接斜率优化,给每个颜色的数开一个单调栈即可. #include<cstdio> #include<vector> #include< ...

  3. 【bzoj4709】[Jsoi2011]柠檬 斜率优化

    题目描述 给你一个长度为 $n$ 的序列,将其分成若干段,每段选择一个数,获得 $这个数\times 它在这段出现次数的平方$ 的价值.求最大总价值. $n\le 10^5$ . 输入 第 1 行:一 ...

  4. bzoj 4709 [ Jsoi2011 ] 柠檬 —— 斜率优化DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4709 课上讲的题,还是参考了博客...:https://www.cnblogs.com/GX ...

  5. 【题解】Cats Transport (斜率优化+单调队列)

    [题解]Cats Transport (斜率优化+单调队列) # When Who Problem Lang Verdict Time Memory 55331572 Jun/09/2019 19:1 ...

  6. 【BZOJ 4709】柠檬 斜率优化dp+单调栈

    题意 给$n$个贝壳,可以将贝壳分成若干段,每段选取一个贝壳$s_i$,这一段$s_i$的数目为$num$,可以得到$num^2\times s_i$个柠檬,求最多能得到几个柠檬 可以发现只有在一段中 ...

  7. BZOJ4709 Jsoi2011 柠檬【决策单调性+单调栈】

    Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N ≤ 100,000) 只,按顺序串在树枝上.为了方便,我们从 ...

  8. [BZOJ4709][JSOI2011]柠檬 决策单调性优化dp

    题解: 解法1: 单调栈优化 首先发现一个性质就是 如果当前从i转移比从j转移更加优秀 那么之后就不会从j转移 所以我们考虑利用这个性质 我们要维护一个队列保证前一个超过后一个的时间单调不减 怎么来维 ...

  9. bzoj4709 [jsoi2011]柠檬

    Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N  ≤ 100,000) 只,按顺序串在树枝上.为了方便,我们 ...

随机推荐

  1. HTML-HTML5+CSS3权威指南阅读(三、CSS选择器)

    1.伪元素选择器 first-line, first-letter, before, after 2.属性选择器 [attr*=val]: 如果元素的 attr 属性中包含用 val 指定的字符的话, ...

  2. Ffmpeg 视频教程 向视频中添加文字

    Ffmpeg支持添加文字功能,具体如何将文字叠加到视频中的每一张图片,FFmpeg调用了文字库FreeSerif.ttf.当我们 用到ffmpeg 添加文字功能时 我们需要先下载改文字库,下载地址是h ...

  3. java类的初始化和构造函数

    本人小白一枚,看java类的初始化的时候好晕的说,我觉着书上尽管说的对.但总认为有些信息没说出来,没说清楚,看了好多文章博客的,如今有些感悟,来小写下总结,也算是为以后再次复习种个好果子. 先摘一下书 ...

  4. chrome 浏览器设置字体大小,方便调试

    H5开发的时候,有时候明明字体没有那么大,但在chrome中看上去依然很大.就像型号不对一样,但在手机端是正常的. 这是因为chrome浏览器设置了默认字体.只需要设置一下即可.  「chrome:/ ...

  5. 使用 GROUP BY WITH ROLLUP 改善统计性能

    使用 GROUP BY 的 WITH ROLLUP 字句可以检索出更多的分组聚合信息,它不仅仅能像一般的 GROUP BY 语句那样检索出各组的聚合信息,还能检索出本组类的整体聚合信息. 下面我们的例 ...

  6. Mysql暴错注入代码-webshell

      MySql Error Based Injection Reference[Mysql暴错注入参考]Author:Pnig0s1992Mysql5.0.91下测试通过,对于5+的绝大部分版本可以测 ...

  7. unity, 删除animationEvent

    当初给Player的一个animation加了个animationEvent,后来与之关联的响应函数删除了,于是导致报错: ‘Player’ AnimationEvent ‘idleHalfEvent ...

  8. Memcache应用场景介绍,说明[zz]

    转于:http://www.cnblogs.com/literoad/archive/2012/12/23/2830178.html 面临的问题 对于高并发高访问的 Web应用程序来说,数据库存取瓶颈 ...

  9. keystone WSGI流程

    作为OpenStack两种基本的通信方式(RESTful API与消息总线)之中的一个.理解RESTful API的设计思路和运行过程,有助于我们对OpenStack有更好的理解.RESTful仅仅是 ...

  10. Atitit.prototype-base class-based  基于“类” vs 基于“原型”

    Atitit.prototype-base class-based  基于“类” vs 基于“原型” 1. 基于“类” vs 基于“原型”1 2.  对象的产生有两种基本方式.一种是以原型(proto ...