@desription@

一共有 N 只贝壳,编号为 1...N,贝壳 i 的大小为 si。

Flute 每次可以取一段连续的贝壳,并选择 s0。如果这些贝壳中大小为 s0 的贝壳有 t 只,就通过魔法把这些贝壳变成 s0*t^2 只柠檬。

经过任意次魔法取完贝壳,最终 Flute 得到的柠檬数是所有小段柠檬数的总和。问最多能变出多少柠檬。

input

第 1 行:一个整数,表示 N(1 ≤ N ≤ 100,000)。

第 2 .. N + 1 行:每行一个整数,第 i + 1 行表示 si(1 ≤ si ≤10,000)。

output

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

sample input

5

2

2

5

2

3

sample output

21

sample explain

Flute 先从取下 4 只贝壳,它们的大小为 2, 2, 5, 2。选择 s0 = 2,那么这一段

里有 3 只大小为 s0 的贝壳,通过魔法可以得到 2×3^2 = 18 只柠檬。再从右端取下最后一只贝壳,通过魔法可以得到 1×3^1 = 3 只柠檬。总共可以得到 18 + 3 = 21 只柠檬。没有比这更优的方案了。

@solution@

有这样一个性质:假如你对于区间 [l, r] 选的贝壳大小为 s0,则贝壳 l 与 r 的大小为 s0。

如果区间的左右端点的大小不为 s0,则你可以往内缩端点直到等于为止,此时这个区间的答案不会变化。

这样我们就可以来设计 dp 了。

定义状态 \(dp[i]\) 表示取完 1~i 这些贝壳所能求得的最大柠檬数,再定义 \(f[i]\) 表示 i 前面的,与 i 大小相同的贝壳数量(类前缀和)。

则有状态转移:

\[dp[i] = dp[j-1] + s[i]*(f[i]-f[j]+1)*(f[i]-f[j]+1) (s[i] = s[j]且j \leq i)
\]

长得非常 “斜率优化”,我们拆开括号再仔细来看一看:

\[dp[i] = dp[j-1] + s[i]*(f[i]+1)^2-2*s[i]*f[i]*f[j]+s[i]*f[j]^2
\]

注意 s[i] = s[j]。所以式子还可以变为:

\[dp[i] = (dp[j-1]+s[j]*f[j]^2) + (s[i]*(f[i]+1)^2)-2*s[i]*f[i]*f[j]
\]

然后就可以斜率优化了。其中横坐标 \(x[j] = 2*f[j]\),纵坐标 \(y[j] = dp[j-1]+s[j]*f[j]^2\),斜率 \(k[i]=s[i]*f[i]\)。

我们对于每一个 \(s[i]\) 分别进行斜率优化,斜率 \(s[i]*f[i]\) 是单增的,横坐标 \(2*f[j]\) 也是单增,求最大值即上凸包,对于每一个 \(s[i]\) 都开一个单调栈就 OK 了。

讲一点代码细节:同时维护多个单调栈可以不用 vector 或者 deque 等动态的存储,因为我们已知了所有不同类型的 si 对应的元素个数,所以它的单调栈长度必然不会超过这个值。

我们开一个总的长度为 N 的空间,然后按照元素个数分配栈顶的指针即可。

@accepted code@

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 100000;
const int MAXS = 10000;
ll dp[MAXN + 5], sum[MAXN + 5];
int nxt[MAXN + 5], adj[MAXN + 5], s[MAXN + 5];
ll c(int i) {return (sum[i] + 1)*(sum[i] + 1)*s[i];}
ll k(int i) {return 2LL*s[i]*(sum[i] + 1);}
ll x(int j) {return sum[j];}
ll y(int j) {return dp[j-1] + sum[j]*sum[j]*s[j];}
double slope(int p, int q) {return 1.0*(y(p) - y(q))/(x(p) - x(q));}
int stk[MAXN + 5], tp[MAXS + 5], cnt[MAXS + 5];
int main() {
int N; scanf("%d", &N);
for(int i=1;i<=N;i++) {
scanf("%d", &s[i]);
sum[i] = sum[adj[s[i]]] + 1;
nxt[i] = adj[s[i]];
adj[s[i]] = i;
cnt[s[i]]++;
}
for(int i=1;i<=MAXS;i++)
cnt[i] += cnt[i-1];
for(int i=1;i<=MAXS;i++)
tp[i] = cnt[i-1];
for(int i=1;i<=N;i++) {
while( tp[s[i]] > cnt[s[i]-1] + 1 && slope(stk[tp[s[i]]], i) >= slope(stk[tp[s[i]] - 1], stk[tp[s[i]]]) )
tp[s[i]]--;
stk[++tp[s[i]]] = i;
while( tp[s[i]] > cnt[s[i]-1] + 1 && slope(stk[tp[s[i]] - 1], stk[tp[s[i]]]) <= k(i) )
tp[s[i]]--;
dp[i] = c(i) + y(stk[tp[s[i]]]) - k(i)*x(stk[tp[s[i]]]);
}
printf("%lld\n", dp[N]);
}

@details@

一开始我想的是对于每一个 si 都从头到尾作一遍 dp,这样就只需要一个单调栈了。

后来发现,不同的 si 之间也会相互影响,所以我只能从前往后老老实实维护多个单调栈了……

@bzoj - 4709@ 柠檬的更多相关文章

  1. bzoj 4709 [Jsoi2011]柠檬——单调栈二分处理决策单调性

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4709 题解:https://blog.csdn.net/neither_nor/articl ...

  2. bzoj 4709: [Jsoi2011]柠檬

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

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

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

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

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

  5. 单调性优化DP

    单调性优化DP Tags:动态规划 作业部落链接 一.概述 裸的DP过不了,怎么办? 通常会想到单调性优化 单调队列优化 斜率优化 决策单调性 二.题目 [x] 洛谷 P2120 [ZJOI2007] ...

  6. bzoj 2216 [Poi2011]Lightning Conductor——单调队列+二分处理决策单调性

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2216 那个关于位置的代价是带根号的,所以随着距离的增加而增长变慢:所以靠后的位置一旦比靠前的 ...

  7. 【BZOJ】4709: [Jsoi2011]柠檬

    4709: [Jsoi2011]柠檬 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 779  Solved: 310[Submit][Status][ ...

  8. 4709: [Jsoi2011]柠檬

    4709: [Jsoi2011]柠檬 https://www.lydsy.com/JudgeOnline/problem.php?id=4709 分析: 决策单调性+栈+二分. 首先挖掘性质:每个段选 ...

  9. 1502: [NOI2005]月下柠檬树 - BZOJ

    Description Input 文件的第1行包含一个整数n和一个实数alpha,表示柠檬树的层数和月亮的光线与地面夹角(单位为弧度).第2行包含n+1个实数h0,h1,h2,…,hn,表示树离地的 ...

随机推荐

  1. docker-4-Dockerfile配置文件详解

    ​ Dockerfile简单一点就是描述你这个镜像安装了哪些软件包,有哪些操作,创建了什么东西.有些人喜欢用 docker commit 命令去打包镜像,这样是不好的,首先commit出来的镜像比你使 ...

  2. CentOS7 安装 Nginx 1.12.1

    安装准备: nginx 依赖的一些 lib 库: yum install gcc-c++ yum install pcre pcre-devel yum install zlib zlib-devel ...

  3. 2019-10-18-WPF-解决-StylusPlugIn-点击穿透问题

    title author date CreateTime categories WPF 解决 StylusPlugIn 点击穿透问题 lindexi 2019-10-18 20:55:35 +0800 ...

  4. linux压缩打包

    linux下的压缩命令有tar.gzip.gunzip.bzip2.bunzip2. compress.uncompress.zip.unzip.rar.unrar等等,压缩后的扩展名有.tar..g ...

  5. Nginx 编译设置模块执行顺序

    Nginx编译时,配置"--add-module=xxx"可以加入模块,当我们需要按照指定顺序来设置过滤模块执行顺序时,先配置的"--add-module=xxx&quo ...

  6. Leetcode63.Unique Paths II不同路径2

    一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为"Start" ). 机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角(在下图中标记为" ...

  7. Linux系统下实现远程连接MySQL数据库的方法教程

    1.在服务器端开启远程访问首先进入mysql数据库,然后输入下面两个命令: grant all privileges on *.* to 'root'@'%' identified by 'passw ...

  8. 【CS Round #44 (Div. 2 only) B】Square Cover

    [链接]点击打开链接 [题意] 给你一个n*m的矩形,让你在其中圈出若干个子正方形,使得这些子正方形里面的所有数字都是一样的. 且一样的数字,都是在同一个正方形里面.问你有没有方案. [题解] 相同的 ...

  9. python-null

    很早之前,遇到过一个面试官问的python中有没有null,当时有点紧张,想成了None,就脱口而出是有的.今天遇到了none问题,所以就正好说一下. python中是没有NULL的. Python中 ...

  10. JavaScript 防抖和节流

    1. 概述 1.1 说明 在项目过程中,经常会遇到一个按钮被多次点击并且多次调用对应处理函数的问题,而往往我们只需去调用一次处理函数即可.有时也会遇到需要在某一规则内有规律的去触发对应的处理函数,所以 ...