@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. torch.backends.cudnn.benchmark = true 使用情形

    设置这个 flag 可以让内置的 cuDNN 的 auto-tuner 自动寻找最适合当前配置的高效算法,来达到优化运行效率的问题. 应该遵循以下准则: 如果网络的输入数据维度或类型上变化不大,设置  ...

  2. 直白介绍卷积神经网络(CNN)【转】

    英文地址:https://ujjwalkarn.me/2016/08/11/intuitive-explanation-convnets/ 中文译文:http://mp.weixin.qq.com/s ...

  3. Win7系统中wmiprvse.exe占用CPU高如何解决

    该进程的详细路径是在:C:\WINDOWS\System32\Wbem  我们可以在任务管理器中“wmiprvse.exe”进程上单击右键,选择“打开文件位置”即可看到,如果该文件不在该文件夹中,那么 ...

  4. Python 匹配IP地址的正则表达式

  5. BZOJ1076奖励关题解

    链接 很容易想到状压,f[i][s]表示前i个选择的箱子集合为s的最大期望 果断wa了,因为有一些不合法的状态,譬如f[1][1111001]这样的状态 这样的状态不好排除,所以改用倒推 用f[i][ ...

  6. 如何用KNIME进行情感分析

    Customer Intelligence Social Media Finance Credit Scoring Manufacturing Pharma / Health Care Retail ...

  7. 手机端 echarts使用 svg渲染器

    // 使用 Canvas 渲染器(默认) var chart = echarts.init(containerDom, null, {renderer: 'canvas'}); // 等价于: var ...

  8. Array操作的方法

    //concat连接数组连接一个或多个数组 //var a = [1,2,3]; //var c=[4,5] //var b = a.concat(c); //console.log(b); //jo ...

  9. 洛谷 P3258 [JLOI2014]松鼠的新家 树链剖分+差分前缀和优化

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 说明 思路 AC代码 优化 优化后AC代码 总结 题面 题目链接 P3258 [JLOI2 ...

  10. EasyUI 网格 一主多从 从表使用自定义树状展开

    <table id="Table1" class="easyui-datagrid" title="标题" style="w ...