题目链接

思路

首先,最优秀的分法一定是每段两端都是这一段中最多的那个,否则可以把不是的那个踢出去单独成段肯定会更优秀。然后就成了将这个序列分段,保证每段两端元素相同的最大收益和。

用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])\)

  1. for(int i=1;i<=n;++i)
  2. for(int j=1;j<=i;++j)
  3. if(a[i]==a[j])
  4. 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)\)代码

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<string>
  5. #include<algorithm>
  6. #include<cstdlib>
  7. #include<map>
  8. #include<queue>
  9. using namespace std;
  10. typedef long long ll;
  11. const int N=100000+100;
  12. ll read() {
  13. ll x=0,f=1; char c=getchar();
  14. while(c<'0'||c>'9') {
  15. if(c=='-') f=-1;
  16. c=getchar();
  17. }
  18. while(c>='0'&&c<='9') {
  19. x=x*10+c-'0';
  20. c=getchar();
  21. }
  22. return x*f;
  23. }
  24. int n;
  25. int a[N],s[N],c[N];
  26. ll f[N];
  27. int main() {
  28. n=read();
  29. for(int i=1;i<=n;++i) {
  30. a[i]=read();
  31. s[i]=++c[a[i]];
  32. }
  33. for(int i=1;i<=n;++i)
  34. for(int j=1;j<=i;++j)
  35. if(a[i]==a[j])
  36. f[i]=max(f[i],f[j-1]+a[i]*(s[i]-s[j]+1)*(s[i]-s[j]+1));
  37. cout<<f[n];
  38. return 0;
  39. }

\(O(n)\)代码

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<string>
  5. #include<algorithm>
  6. #include<cstdlib>
  7. #include<map>
  8. #include<bits/stdc++.h>
  9. #include<queue>
  10. #include<vector>
  11. using namespace std;
  12. typedef long long ll;
  13. const int N=100000+100;
  14. ll read() {
  15. ll x=0,f=1; char c=getchar();
  16. while(c<'0'||c>'9') {
  17. if(c=='-') f=-1;
  18. c=getchar();
  19. }
  20. while(c>='0'&&c<='9') {
  21. x=x*10+c-'0';
  22. c=getchar();
  23. }
  24. return x*f;
  25. }
  26. vector<int> sta[N];
  27. int a[N],s[N],c[N];
  28. ll f[N];
  29. ll calc(int x,int y) {
  30. return f[x-1]+(ll)a[x]*y*y;
  31. }
  32. int n;
  33. int find(int x,int y) {//寻找x比y优秀的最早时间
  34. int l=1,r=n;
  35. int ans=n+1;
  36. while(l<=r) {
  37. int mid=l+r>>1;
  38. if(calc(x,mid-s[x]+1)>=calc(y,mid-s[y]+1)) ans=mid,r=mid-1;
  39. else l=mid+1;
  40. }
  41. return ans;
  42. }
  43. int main() {
  44. n=read();
  45. for(int i=1;i<=n;++i) {
  46. a[i]=read();
  47. s[i]=++c[a[i]];
  48. }
  49. for(int i=1;i<=n;++i) {
  50. 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]))
  51. sta[a[i]].pop_back();
  52. sta[a[i]].push_back(i);
  53. 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]) {
  54. sta[a[i]].pop_back();
  55. }
  56. int now=sta[a[i]].size();
  57. f[i]=calc(sta[a[i]][now-1],s[i]-s[sta[a[i]][now-1]]+1);
  58. }
  59. cout<<f[n];
  60. }

[bzoj4709][柠檬]的更多相关文章

  1. bzoj4709 柠檬 单调栈,DP,斜率优化

    目录 前言吐槽 思路 错误 代码 /* 前言吐槽 我真的不知道是咋做的 不过大约就是栈的斜率优化 哪位大佬见识广,给看看吧(乞讨) 思路 s是值等于a[i]的前缀和 转移方程$f[i]=max(f[i ...

  2. Noip前的大抱佛脚----赛前任务

    赛前任务 tags:任务清单 前言 现在xzy太弱了,而且他最近越来越弱了,天天被爆踩,天天被爆踩 题单不会在作业部落发布,所以可(yi)能(ding)会不及时更新 省选前的练习莫名其妙地成为了Noi ...

  3. bzoj4709: [Jsoi2011]柠檬 斜率优化

    题目链接 bzoj4709: [Jsoi2011]柠檬 题解 斜率优化 设 \(f[i]\) 表示前 \(i\)个数分成若干段的最大总价值. 对于分成的每一段,左端点的数.右端点的数.选择的数一定是相 ...

  4. 【BZOJ4709】柠檬(动态规划,单调栈)

    [BZOJ4709]柠檬(动态规划,单调栈) 题面 BZOJ 题解 从左取和从右取没有区别,本质上就是要分段. 设\(f[i]\)表示前\(i\)个位置的最大值. 那么相当于我们枚举一个前面的位置\( ...

  5. 【BZOJ4709】[Jsoi2011]柠檬 斜率优化+单调栈

    [BZOJ4709][Jsoi2011]柠檬 Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N ≤ 100,0 ...

  6. bzoj4709 [jsoi2011]柠檬

    Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N  ≤ 100,000) 只,按顺序串在树枝上.为了方便,我们 ...

  7. 【bzoj4709】[Jsoi2011]柠檬 斜率优化

    题目描述 给你一个长度为 $n$ 的序列,将其分成若干段,每段选择一个数,获得 $这个数\times 它在这段出现次数的平方$ 的价值.求最大总价值. $n\le 10^5$ . 输入 第 1 行:一 ...

  8. BZOJ4709 Jsoi2011 柠檬【决策单调性+单调栈】

    Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N ≤ 100,000) 只,按顺序串在树枝上.为了方便,我们从 ...

  9. BZOJ4709 JSOI2011柠檬(动态规划)

    首先要冷静下来发现这仅仅是在划分区间.显然若有相邻的数字相同应当划分在同一区间.还有一个显然的性质是区间的两端点应该相同且选择的就是端点的数.瞬间暴力dp就变成常数极小100002了.可以继续斜率优化 ...

随机推荐

  1. 并行管理工具——pdsh

    1. pdsh安装2. pdsh常规使用2.1 pdsh2.2 pdcp 并行管理的方式有很多种: 命令行 一般是for循环 脚本 一般是expect+ssh等自编辑脚本 工具 pssh,pdsh,m ...

  2. 【nodejs】让nodejs像后端mvc框架(asp.net mvc )一样处理请求--路由限制及选择篇(2/8)【route】

    文章目录 前情概要 上文中的RouteHandler中有一个重要方法GetActionDescriptor没有贴代码和说,接下来我们就说一说这个方法. 使用controllerName.actionN ...

  3. MySQL高可用架构-MMM环境部署记录

    MMM介绍MMM(Master-Master replication manager for MySQL)是一套支持双主故障切换和双主日常管理的脚本程序.MMM使用Perl语言开发,主要用来监控和管理 ...

  4. javaScript——DOM1级,DOM2级,DOM3级

    DOM0,DOM2,DOM3事件处理方式区别:http://www.qdfuns.com/notes/11861/e21736a0b15bceca0dc7f76d77c2fb5a.html JS中do ...

  5. LINUX内核分析第五周学习总结——扒开系统调用的“三层皮”(下)

    LINUX内核分析第五周学习总结--扒开系统调用的"三层皮"(下) 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>M ...

  6. iOS 模拟器“安装”app

    1.首先在模拟器上运行我们的app程序 2.执行以下命令: ditto -ck --sequesterRsrc --keepParent `ls - -d -t ~/Library/Developer ...

  7. 去掉ambiguous expansion of macro警告

    查看原文:http://www.heyuan110.com/?p=1221 用pod install后,pod工程里出现ambiguous expansion of macro的warning,对于有 ...

  8. jeecg 主-附表生成代码例子

    jeecg 主-附表生成代码例子 - CSDN博客https://blog.csdn.net/u010411264/article/details/51243277 JEECG Online Codi ...

  9. MYSQL ROW_FORMAT=Compact

    https://dev.mysql.com/doc/refman/5.6/en/innodb-row-format-antelope.html https://docs.oracle.com/cd/E ...

  10. Jmeter 常用断言使用

    响应断言 可根据要测试响应字段和模式匹配规则来设置断言,比如下方截图是匹配返回的结果中是否包含"code:200,",如果包含则表示断言成功,否则失败.响应断言可添加多个,但是多个 ...