【BZOJ4709】【Jsoi2011】柠檬
Description
传送门
题意简述:将序列划分成任意多段,从每一段选出一个数\(x\),获得\(在这一段出现的次数x*(x在这一段出现的次数)\)的贡献。求总贡献最大值。
Solution
首先,要发现一个很重要的性质:如果某一段选了\(x\),那么这一段一定是以\(x\)开头、以\(x\)结尾的一段。否则,可以将此段缩减至以\(x\)开头、以\(x\)结尾的更小的一段,虽然贡献没有变,但留给其他段的机会更多。
设\(f_i\)表示\(1...i\)的贡献最大值。记\(a_i\)表示\(i\)的数值,\(b_i\)表示\(a_i\)在相同的值中是第几个出现的。显然如果要从别的\(f_j\)转移到\(f_i\),必须满足\(a_{j+1}==a_i\)。我们有转移方程:
\]
设\(j\)为最优转移点:
f_i&=f_{j-1}+a_i(b_i-(b_j-1))^2\\
f_i&=f_{j-1}+a_i(b_i^2-2b_i(b_j-1)+(b_j-1)^2)\\
f_i&=f_{j-1}+a_ib_i^2-2a_ib_i(b_j-1)+a_i(b_j-1)^2\\
f_{j-1}+a_i(b_j-1)^2&=2a_ib_i(b_j-1)+f_i-a_ib_i^2
\end{aligned}
\]
这其实是一个直线的式子:\(k=2a_ib_i\),\(x=(b_j-1)\),\(b=(f_i-a_ib_i^2)\),\(y=f_{j-1}+a_i(b_j-1)^2\).
其中\(a_i\)看似和\(i\)有关,无法继续推理。但由于转移的\(j\)满足\(a_j=a_i\),所以每一个位置的数在参与上述DP时,相关联的\(a\)其实就是每一个元素自己的数值,是一个定值。
把每一个元素看成二维平面的一个点\((x,y)\)。由于最优转移相当于最大化截距,那么最优转移点\(j\)可以看做在斜率为\(k\)的时候上凸包碰到的第一个点。
那么我们扫描序列时,维护每一个数值对应的上凸包,每次查询时在上面二分即可。
时间复杂度\(\mathcal O(n \lg n)\)。
当然,也可以用斜率优化直接做。
Code
#include <cstdio>
#include <vector>
#define k(i) (2LL*a[i]*b[i])
#define x(i) (b[i]-1LL)
#define y(i) (f[i-1]+1LL*a[i]*(b[i]-1)*(b[i]-1))
#define b(i) (f[i]-1LL*a[i]*b[i]*b[i])
#define pb push_back
#define db pop_back
using namespace std;
typedef long long ll;
const int N=100005,S=10005;
const double EPS=1e-6;
int n,a[N],ecnt[S],b[N];
ll f[N];
vector<int> s[S];
int slen[S];
double slope(int u,int v){return 1.0*(y(v)-y(u))/(x(v)-x(u));}
int query(int col,int k){
k=2*col*k;
int l=0,r=slen[col]-2,mid;
while(l<=r){
mid=(l+r)>>1;
if(slope(s[col][mid],s[col][mid+1])-EPS<=k) r=mid-1;
else l=mid+1;
}
return s[col][l];
}
void insert(int col,int i){
int sz=slen[col];
while(sz>1&&slope(s[col][sz-2],s[col][sz-1])<slope(s[col][sz-1],i))
sz--,slen[col]--,s[col].db();
s[col].pb(i);
slen[col]++;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
b[i]=++ecnt[a[i]];
}
for(int i=1;i<=n;i++){
insert(a[i],i);
int j=query(a[i],b[i]);
f[i]=(j?f[j-1]:f[i-1])+1LL*a[i]*(b[i]-b[j]+1)*(b[i]-b[j]+1);
}
printf("%lld\n",f[n]);
return 0;
}
【BZOJ4709】【Jsoi2011】柠檬的更多相关文章
- bzoj4709: [Jsoi2011]柠檬 斜率优化
题目链接 bzoj4709: [Jsoi2011]柠檬 题解 斜率优化 设 \(f[i]\) 表示前 \(i\)个数分成若干段的最大总价值. 对于分成的每一段,左端点的数.右端点的数.选择的数一定是相 ...
- bzoj4709 [jsoi2011]柠檬
Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N ≤ 100,000) 只,按顺序串在树枝上.为了方便,我们 ...
- BZOJ4709 Jsoi2011 柠檬【决策单调性+单调栈】
Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N ≤ 100,000) 只,按顺序串在树枝上.为了方便,我们从 ...
- BZOJ4709 JSOI2011柠檬(动态规划)
首先要冷静下来发现这仅仅是在划分区间.显然若有相邻的数字相同应当划分在同一区间.还有一个显然的性质是区间的两端点应该相同且选择的就是端点的数.瞬间暴力dp就变成常数极小100002了.可以继续斜率优化 ...
- [BZOJ4709][JSOI2011]柠檬(斜率优化DP)
显然选出的每一段首尾都是相同的,于是直接斜率优化,给每个颜色的数开一个单调栈即可. #include<cstdio> #include<vector> #include< ...
- [BZOJ4709][JSOI2011]柠檬 决策单调性优化dp
题解: 解法1: 单调栈优化 首先发现一个性质就是 如果当前从i转移比从j转移更加优秀 那么之后就不会从j转移 所以我们考虑利用这个性质 我们要维护一个队列保证前一个超过后一个的时间单调不减 怎么来维 ...
- BZOJ4709: [Jsoi2011]柠檬(决策单调性)
题意 题目链接 Sol 结论:每次选择的区间一定满足首位元素相同.. 仔细想想其实挺显然的,如果不相同可以删掉多着的元素,对答案的贡献是相同的 那么设\(f[i]\)表示到第\(i\)个位置的最大价值 ...
- 【BZOJ4709】[Jsoi2011]柠檬 斜率优化+单调栈
[BZOJ4709][Jsoi2011]柠檬 Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N ≤ 100,0 ...
- 4709: [Jsoi2011]柠檬
4709: [Jsoi2011]柠檬 https://www.lydsy.com/JudgeOnline/problem.php?id=4709 分析: 决策单调性+栈+二分. 首先挖掘性质:每个段选 ...
- 【BZOJ4709】柠檬(动态规划,单调栈)
[BZOJ4709]柠檬(动态规划,单调栈) 题面 BZOJ 题解 从左取和从右取没有区别,本质上就是要分段. 设\(f[i]\)表示前\(i\)个位置的最大值. 那么相当于我们枚举一个前面的位置\( ...
随机推荐
- Siki_Unity_3-6_UI框架 (基于UGUI)
Unity 3-6 UI框架 (基于UGUI) 任务1&2&3&4:介绍 && 创建工程 UI框架: 管理场景中所有UI面板 控制面板之间的跳转 如果没有UI框 ...
- Linux常规命令总结
Linux常规命令总结,仅供参考: 系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显 ...
- mysql的安装教程-【linux】
先卸载系统自带的mysql,停止mysql:service mysql stop 1.查找以前是否装有mysql命令:rpm -qa|grep -i mysql可以看到mysql的几个包:qt-mys ...
- 木马分析出现python语言,360的安全人员不禁感叹还有这种操作?
几年前,敲诈者木马还是一个默默无闻的木马种类.然而,由于其极强的破坏力和直接且丰厚的财富回报,敲诈者木马这几年已经一跃成为曝光率最高的木马类型——甚至超越了盗号木马.远控木马.网购木马这传统三强.与此 ...
- 如何寻找无序数组中的第K大元素?
如何寻找无序数组中的第K大元素? 有这样一个算法题:有一个无序数组,要求找出数组中的第K大元素.比如给定的无序数组如下所示: 如果k=6,也就是要寻找第6大的元素,很显然,数组中第一大元素是24,第二 ...
- killall命令详解
基础命令学习目录首页 原文链接:https://blog.csdn.net/tanga842428/article/details/52474250 Linux系统中的killall命令用于杀死指定名 ...
- Task 4.2 求一个矩阵的最大子矩阵的和
任务:输入一个二维整形数组,数组里有正数也有负数.二维数组中连续的一个子矩阵组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值.要求时间复杂度为O(n). (1)设计思想:把二维矩阵分解成 ...
- Codeforces Round #341 (Div. 2) E. Wet Shark and Blocks dp+矩阵加速
题目链接: http://codeforces.com/problemset/problem/621/E E. Wet Shark and Blocks time limit per test2 se ...
- 【CS231N】5、神经网络静态部分:数据预处理等
一.疑问 二.知识点 1. 白化 白化操作的输入是特征基准上的数据,然后对每个维度除以其特征值来对数值范围进行归一化.该变换的几何解释是:如果数据服从多变量的高斯分布,那么经过白化后,数据的分布将 ...
- json反序列化对象
这个是同事研究的wcf中中根据type类型反序列化json的示例 /// <summary> /// json转对象 /// </summary> /// <param ...