【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\)个位置的最大值. 那么相当于我们枚举一个前面的位置\( ...
随机推荐
- phpcmsv9广告版位调用方法
<div class="ya"> <?php // pc:get 使用sql语句获取指定条件的广告版位! ?> {pc:get sql="SELE ...
- 利用jsencrypt 做非对称加密
1.生成 private key openssl genrsa -out rsa_1024_priv.pem 1024 2.生成public key openssl rsa -pubout -in r ...
- Windows ,获取硬盘物理序列号(VC++)
#include <windows.h> BOOL GetHDID(PCHAR pIDBufer) { HANDLE hDevice=NULL; hDevice=::Crea ...
- 离线人脸识别 ArcFaceSharp -- ArcFace 2.0 SDK C#封装库分享
ArcFaceSharp ArcFaceSharp 是ArcSoft 虹软 ArcFace 2.0 SDK 的一个 C# 封装库,为方便进行 C# 开发而封装.欢迎 Start & Fork. ...
- Ubuntu16.04安装搜狗拼音输入法
为了让自己的电脑相对安全一些,我安装了ubuntu的物理机 因为要经常输入汉字,我就在unbuntu里面安装了搜狗输入法 1.在搜狗输入法官网下载Linux版本的安装包:https://pinyin. ...
- 笨办法学Python - 习题3: Numbers and Math
目录 习题 3: 数字和数学计算 算术运算符 加分习题: 我的答案: 总结: 扩展: Python比较运算符 Python赋值运算符 Python位运算符 Python逻辑运算符 Python成员运算 ...
- 第26次Scrum会议(11/14)【欢迎来怼】
一.小组信息 队名:欢迎来怼小组成员队长:田继平成员:李圆圆,葛美义,王伟东,姜珊,邵朔,阚博文 小组照片 二.开会信息 时间:2017/11/14 11:35~11:57,总计22min.地点:东北 ...
- Beta发布文案+美工
团队名称:探路者 1蔺依铭:http://www.cnblogs.com/linym762/(组长) 2张恩聚:http://www.cnblogs.com/zej87/ 3米赫:http://www ...
- Java里字符串split方法
Java中的split方法以"."切割字符串时,需要转义 String str[] = s.split("\\.");
- CS小分队第二阶段冲刺站立会议(6月3日)
昨日成果:完成了主界面按钮移动交换位置 遇到问题:最后的时候发现仅交换了按钮在数据库中的信息,对于按钮的链接忘记交换了 今日计划:解决这个问题,对这个冲刺阶段的成果进行整理