[bzoj4709][柠檬]
思路
首先,最优秀的分法一定是每段两端都是这一段中最多的那个,否则可以把不是的那个踢出去单独成段肯定会更优秀。然后就成了将这个序列分段,保证每段两端元素相同的最大收益和。
用a[i]记录第i个位置上的数,用s[i]记录前i个元素中a[i]出现的次数。f[i]表示以前i个数的最大收益。
首先考虑\(n^2\)的dp。明显\(f[i]=max\{f[j]+a[i]*(s[i]-s[j]+1)^2\} (a[i]==a[j])\)
for(int i=1;i<=n;++i)
for(int j=1;j<=i;++j)
if(a[i]==a[j])
f[i]=max(f[i],f[j-1]+a[i]*(s[i]-s[j]+1)*(s[i]-s[j]+1));
然后可发现,在上面的式子中,s数组是单增的,f数组也是单增的。如果知道了两个位置x和y(x<y)。通过二分,可以找到一个now使得当以后的某个位置pos的s[pos]>now之后的所有位置用x转移会比y优秀,这时y就没用了。所以用一个单调栈维护即可。
\(O(n^2)\)代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const int N=100000+100;
ll read() {
ll x=0,f=1; char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
int n;
int a[N],s[N],c[N];
ll f[N];
int main() {
n=read();
for(int i=1;i<=n;++i) {
a[i]=read();
s[i]=++c[a[i]];
}
for(int i=1;i<=n;++i)
for(int j=1;j<=i;++j)
if(a[i]==a[j])
f[i]=max(f[i],f[j-1]+a[i]*(s[i]-s[j]+1)*(s[i]-s[j]+1));
cout<<f[n];
return 0;
}
\(O(n)\)代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<map>
#include<bits/stdc++.h>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const int N=100000+100;
ll read() {
ll x=0,f=1; char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
vector<int> sta[N];
int a[N],s[N],c[N];
ll f[N];
ll calc(int x,int y) {
return f[x-1]+(ll)a[x]*y*y;
}
int n;
int find(int x,int y) {//寻找x比y优秀的最早时间
int l=1,r=n;
int ans=n+1;
while(l<=r) {
int mid=l+r>>1;
if(calc(x,mid-s[x]+1)>=calc(y,mid-s[y]+1)) ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
int main() {
n=read();
for(int i=1;i<=n;++i) {
a[i]=read();
s[i]=++c[a[i]];
}
for(int i=1;i<=n;++i) {
while(sta[a[i]].size()>=2&&find(sta[a[i]][sta[a[i]].size()-1],i)>=find(sta[a[i]][sta[a[i]].size()-2],sta[a[i]][sta[a[i]].size()-1]))
sta[a[i]].pop_back();
sta[a[i]].push_back(i);
while(sta[a[i]].size()>=2&&find(sta[a[i]][sta[a[i]].size()-2],sta[a[i]][sta[a[i]].size()-1])<=s[i]) {
sta[a[i]].pop_back();
}
int now=sta[a[i]].size();
f[i]=calc(sta[a[i]][now-1],s[i]-s[sta[a[i]][now-1]]+1);
}
cout<<f[n];
}
[bzoj4709][柠檬]的更多相关文章
- bzoj4709 柠檬 单调栈,DP,斜率优化
目录 前言吐槽 思路 错误 代码 /* 前言吐槽 我真的不知道是咋做的 不过大约就是栈的斜率优化 哪位大佬见识广,给看看吧(乞讨) 思路 s是值等于a[i]的前缀和 转移方程$f[i]=max(f[i ...
- Noip前的大抱佛脚----赛前任务
赛前任务 tags:任务清单 前言 现在xzy太弱了,而且他最近越来越弱了,天天被爆踩,天天被爆踩 题单不会在作业部落发布,所以可(yi)能(ding)会不及时更新 省选前的练习莫名其妙地成为了Noi ...
- bzoj4709: [Jsoi2011]柠檬 斜率优化
题目链接 bzoj4709: [Jsoi2011]柠檬 题解 斜率优化 设 \(f[i]\) 表示前 \(i\)个数分成若干段的最大总价值. 对于分成的每一段,左端点的数.右端点的数.选择的数一定是相 ...
- 【BZOJ4709】柠檬(动态规划,单调栈)
[BZOJ4709]柠檬(动态规划,单调栈) 题面 BZOJ 题解 从左取和从右取没有区别,本质上就是要分段. 设\(f[i]\)表示前\(i\)个位置的最大值. 那么相当于我们枚举一个前面的位置\( ...
- 【BZOJ4709】[Jsoi2011]柠檬 斜率优化+单调栈
[BZOJ4709][Jsoi2011]柠檬 Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N ≤ 100,0 ...
- bzoj4709 [jsoi2011]柠檬
Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N ≤ 100,000) 只,按顺序串在树枝上.为了方便,我们 ...
- 【bzoj4709】[Jsoi2011]柠檬 斜率优化
题目描述 给你一个长度为 $n$ 的序列,将其分成若干段,每段选择一个数,获得 $这个数\times 它在这段出现次数的平方$ 的价值.求最大总价值. $n\le 10^5$ . 输入 第 1 行:一 ...
- BZOJ4709 Jsoi2011 柠檬【决策单调性+单调栈】
Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N ≤ 100,000) 只,按顺序串在树枝上.为了方便,我们从 ...
- BZOJ4709 JSOI2011柠檬(动态规划)
首先要冷静下来发现这仅仅是在划分区间.显然若有相邻的数字相同应当划分在同一区间.还有一个显然的性质是区间的两端点应该相同且选择的就是端点的数.瞬间暴力dp就变成常数极小100002了.可以继续斜率优化 ...
随机推荐
- ExtJS初探:了解 Ext Core
Ext Core是一款和jQuery媲美的轻型JS库,基于MIT许可.对于Dom的操作,我个人还是比较喜欢用jQuery.当然如果项目中用的是ExtJS框架,也就没必要多引用一个jQuery,Ext ...
- AnyProxy做App网络流量测试
前言: AnyProxy是一个开放式的HTTP代理服务器.Github主页:[https://github.com/alibaba/anyproxy]主要特性包括: 基于Node.js,开放二次开发能 ...
- linux内实践核分析模块
- 在Java中执行Tomcat中startup.bat
问题:更改数据库时,需要重启Tomcat服务器,才能把更改后的数据加载到项目中.于是想每次更改数据库时,都调用Java方法,重启Tomcat 代码: Process process = Runtime ...
- 13.14.15.16.17&《一个程序猿的生命周期》读后感
13.TDS 的标准是什么,怎么样才能认为他是一个标准的TDS?? 14.软件的质量包括哪些方面,如何权衡软件的质量? 15.如何解决功能与时间的矛盾,优秀的软件团队会发布有已知缺陷的软件么? 16. ...
- shell脚本--shift参数左移
参数左移什么意思呢?这个参数指的是在运行脚本时,跟在脚本名后面的参数,前面已经讲过,可以使用$#来获取参数的个数,使用$*来获取所有的参数,而参数左移的含义是这样的:有个指针指向参数列表第一个参数,左 ...
- [转帖] ASP ASPX 等知识
asp.asp.net..aspx..ascx..ashx的简单说明 https://www.cnblogs.com/jhcelue/p/6736147.html ASP是动态server页面(Act ...
- linux_目录基本操作
ls命令 ls命令用来显示目标列表,在Linux中是使用率较高的命令.ls命令的输出信息可以进行彩色加亮显示,以分区不同类型的文件. 语法 $ ls [选项] [目录] 选项 说明 -a 显示所有档案 ...
- Delphi中的构造函数的override的问题
TObject的构造方法Create不能被override.因为它是一个静态方法.
- Visual Studio Code之常备快捷键
官方快捷键大全:https://code.visualstudio.com/docs/customization/keybindings Visual Studio Code是个牛逼的编辑器,启动非常 ...