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 只柠檬。没有比这更优的方案了。
思路
首先发现一个性质
对于选出来的每个区间,区间左端点种类和区间右端点相等,而且这一段区间选定的一定是端点的值,否则一定可以分离出没有用的区间另外计算贡献
然后我们发现对于任意的\(j_1<j_2<i_1<i_2\)
因为每一个种类的前缀和是单调递增的,且\(y=x^2\)是个下凸函数,所以如果在\(i_1\)处\(j_1\)比\(j_2\)更优,有\(i_2\)的时候\(j_1\)一定比\(j_2\)优
所以就可以对每个种类维护一个单调栈
这样就可以维护最优的决策点
但是为了保证决策和斜率都是单调的,在加入节点前我们可以判断,如果栈顶-1超过栈顶的最小前缀大小小于等于站顶超过当前节点的最小前缀大小,那么栈顶是无效的
然后在加入之后判断栈顶-1超过栈顶的前缀大小小于等于当前前缀最小,那么栈顶已经不优秀了,直接弹栈就可以了
//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define for_up(a, b, c) for (int a = b; a <= c; ++a)
#define for_down(a, b, c) for (int a = b; a >= c; --a)
#define for_vector(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x) {
bool w = 1;x = 0;
char c = getchar();
while (!isdigit(c) && c != '-') c = getchar();
if (c == '-') w = 0, c = getchar();
while (isdigit(c)) {
x = (x<<1) + (x<<3) + c -'0';
c = getchar();
}
if (!w) x = -x;
}
template <typename T>
void Write(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9) Write(x / 10);
putchar(x % 10 + '0');
}
//----------------------------------------------
const int N = 1e5 + 10;
const int M = 1e4 + 10;
ll dp[N];
int n, a[N];
int pre[N], last[N], s[N];
vector<int> p[M];
ll cal(int lastpos, int vl) {
return dp[lastpos - 1] + 1ll * a[lastpos] * vl * vl;
}
int check(int x, int y) { // 算x点超过y点的最小前缀和
int l = 1, r = n, ans = n + 1;
while (l <= r) {
int mid = (l + r) >> 1;
if(cal(x, mid - s[x] + 1) >= cal(y, mid - s[y] + 1)) ans = mid , r = mid - 1;
else l = mid + 1;
}
return ans;
}
#define S(s) (signed)s.size()
#define R1(s) S(s) - 1
#define R2(s) S(s) - 2
#define now p[a[i]]
int main() {
Read(n);
for_up(i, 1, n) {
Read(a[i]);
last[i] = pre[a[i]];
s[i] = s[last[i]] + 1;
pre[a[i]] = i;
}
for_up(i, 1, n) {
while (S(now) > 1 && check(now[R2(now)], now[R1(now)]) <= check(now[R1(now)], i)) now.pop_back();
now.push_back(i);
while (S(now) > 1 && check(now[R2(now)], now[R1(now)]) <= s[i]) now.pop_back();
dp[i] = cal(now[R1(now)], s[i] - s[now[R1(now)]] + 1ll);
}
Write(dp[n]);
return 0;
}
BZOJ4709 Jsoi2011 柠檬【决策单调性+单调栈】的更多相关文章
- [BZOJ4709][JSOI2011]柠檬 决策单调性优化dp
题解: 解法1: 单调栈优化 首先发现一个性质就是 如果当前从i转移比从j转移更加优秀 那么之后就不会从j转移 所以我们考虑利用这个性质 我们要维护一个队列保证前一个超过后一个的时间单调不减 怎么来维 ...
- BZOJ4709: [Jsoi2011]柠檬(决策单调性)
题意 题目链接 Sol 结论:每次选择的区间一定满足首位元素相同.. 仔细想想其实挺显然的,如果不相同可以删掉多着的元素,对答案的贡献是相同的 那么设\(f[i]\)表示到第\(i\)个位置的最大价值 ...
- 【BZOJ4709】[Jsoi2011]柠檬 斜率优化+单调栈
[BZOJ4709][Jsoi2011]柠檬 Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N ≤ 100,0 ...
- 【bzoj4709】[Jsoi2011]柠檬 决策单调性+dp
Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N ≤ 100,000) 只,按顺序串在树枝上.为了方便,我们从 ...
- bzoj4709: [Jsoi2011]柠檬 斜率优化
题目链接 bzoj4709: [Jsoi2011]柠檬 题解 斜率优化 设 \(f[i]\) 表示前 \(i\)个数分成若干段的最大总价值. 对于分成的每一段,左端点的数.右端点的数.选择的数一定是相 ...
- bzoj4709 [jsoi2011]柠檬
Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N ≤ 100,000) 只,按顺序串在树枝上.为了方便,我们 ...
- [BZOJ4709][JSOI2011]柠檬(斜率优化DP)
显然选出的每一段首尾都是相同的,于是直接斜率优化,给每个颜色的数开一个单调栈即可. #include<cstdio> #include<vector> #include< ...
- BZOJ4709 JSOI2011柠檬(动态规划)
首先要冷静下来发现这仅仅是在划分区间.显然若有相邻的数字相同应当划分在同一区间.还有一个显然的性质是区间的两端点应该相同且选择的就是端点的数.瞬间暴力dp就变成常数极小100002了.可以继续斜率优化 ...
- DP的各种优化(动态规划,决策单调性,斜率优化,带权二分,单调栈,单调队列)
前缀和优化 当DP过程中需要反复从一个求和式转移的话,可以先把它预处理一下.运算一般都要满足可减性. 比较naive就不展开了. 题目 [Todo]洛谷P2513 [HAOI2009]逆序对数列 [D ...
随机推荐
- 贯众云平台脚本编写之判断、循环以及shell命令的使用
最近使用贯众云平台工具写脚本,进行Ui界面的自动化测试.刚开始接触,确实碰到不少的问题,稍微难点的就是判断语句,循环语句以及shell命令的使用,尤其是对于咱们测试这样比较少接触代码的人来说. 其实吧 ...
- 机器学习笔记—混合高斯和 EM 算法
本文介绍密度估计的 EM(Expectation-Maximization,期望最大). 假设有 {x(1),...,x(m)},因为是无监督学习算法,所以没有 y(i). 我们通过指定联合分布 p( ...
- springboot获取配置文件中的内容
代码: GrilApplication.java @SpringBootApplication public class GrilApplication { public static void ma ...
- js中的内部属性与delete操作符
本文正式地址:http://www.xiabingbao.com/javascript/2015/08/03/javascript-delete-configurable 在讲解Configurabl ...
- Kinect研究文档
1. Kinect主要脚本介绍 1.1 KinectManager脚本 控制传感器并轮询数据流, 下图是参数详解: 公共API网址:https://ratemt.com/k2gpapi/annot ...
- 代码题 — 剑指offer题目、总结
剑指offer题目总结: https://www.cnblogs.com/dingxiaoqiang/category/1117681.html 版权归作者所有,任何形式转载请联系作者.作者:马孔多 ...
- Django WSGI,MVC,MTV,中间件部分,Form初识
一.什么是WSGI? WEB框架的本质是一个socket服务端接收用户请求,加工数据返回给客户端(Django),但是Django没有自带socket需要使用 别人的 socket配合Django才能 ...
- LeetCode OJ:Add and Search Word - Data structure design(增加以及搜索单词)
Design a data structure that supports the following two operations: void addWord(word) bool search(w ...
- nodejs之log4js日志记录模块简单配置使用
在我的一个node express项目中,使用了log4js来生成日志并且保存到文件里,生成的文件如下: 文件名字叫:access.log 如果在配置log4js的时候允许了同时存在多个备份log文件 ...
- 获取手机已安装应用的name,bundleIdentitifer
获取手机已安装应用的name,bundleIdentitifer Class c =NSClassFromString(@"LSApplicationWorkspace"); id ...