LuoguP5504 [JSOI2011]柠檬

题目描述

Solution

容易发现一个性质:每一段划分区间的首尾两个元素相同。
因为倘若不相同的话其中至少一个元素也就不产生贡献,将其划分在其他区间一定不会变劣。

因此就可以写出一个简单的O(n2)O(n^2)O(n2)的dpdpdp。
fi=fj−1+(si−sj+1)2(ai=aj)f_i=f_{j-1}+(s_i-s_j+1)^2\;\;\;\;\;\;\;(a_i=a_j) fi​=fj−1​+(si​−sj​+1)2(ai​=aj​)
其中sis_isi​表示在iii之前的与iii相同的元素的个数。

考虑决策单调性:
设有j1<j2<ij_1<j_2<ij1​<j2​<i,aj1=aj2a_{j_1}=a_{j_2}aj1​​=aj2​​,令getans(x,y)getans(x,y)getans(x,y)表示fx−1+(sy−sx+1)2f_{x-1}+(s_y-s_x+1)^2fx−1​+(sy​−sx​+1)2。

若getans(j1,i)≥getans(j2,i)getans(j_1,i)\geq getans(j_2,i)getans(j1​,i)≥getans(j2​,i),则对于所有i′≥ii'\geq ii′≥i,都有getans(j1,i′)≥getans(j2,i′)getans(j_1,i')\geq getans(j_2,i')getans(j1​,i′)≥getans(j2​,i′),因为两者的增长都是平方级别的。

因此我们可以用单调栈维护这一过程。
对于每一种aia_iai​开一个单调栈,我们希望的是保证栈中元素的getans(...,i)getans(...,i)getans(...,i)始终递增。每次如果发现栈顶元素没有它下面一个元素优,就弹栈。

但这并不是完全正确的,随着iii的后移,因为前面的元素增长快,所以可能存在一个j1<j2<j3<ij_1<j_2<j_3<ij1​<j2​<j3​<i,使得getans(j1,i)>getans(j3,i)getans(j_1,i)>getans(j_3,i)getans(j1​,i)>getans(j3​,i),但getans(j2,i)<getans(j3,i)getans(j_2,i)<getans(j_3,i)getans(j2​,i)<getans(j3​,i)。

因此我们还需要保证栈中每一个元素xxx超过上面一个元素yyy的时间小于yyy超过它上面的元素zzz的时间。

这个某个元素超过另一个元素的时间可以二分求得。

所以我们维护单调栈时额外添加一个判断getans(stack[top−2])>getans(stack[top−1])getans(stack[top-2])>getans(stack[top-1])getans(stack[top−2])>getans(stack[top−1])的时间是否比getans(stack[top−1])>getans(stack[top])getans(stack[top-1])>getans(stack[top])getans(stack[top−1])>getans(stack[top])的时间短即可。

时间复杂度O(nlgn)O(nlgn)O(nlgn)。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se secondusing namespace std;template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=998244353;
const int MAXN=600005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{int f=1,x=0; char c=getchar();while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }return x*f;
}
ll f[MAXN];
vector<int> V[MAXN];
int a[MAXN],s[MAXN],cnt[MAXN],n;
ll Getans(int x,int y) { return f[x-1]+1ll*a[x]*y*y; }
ll getans(int x,int y) { return f[x-1]+1ll*a[x]*(s[y]-s[x]+1)*(s[y]-s[x]+1); }
int check(int x,int y)
{int l=s[y],r=n+1;while (l<r){int mid=(l+r)>>1;if (Getans(x,mid-s[x]+1)>=Getans(y,mid-s[y]+1)) r=mid;else l=mid+1;}return r;
}
int main()
{n=read();for (int i=1;i<=n;i++) s[i]=++cnt[a[i]=read()];f[0]=0;for (int i=1,sz;i<=n;i++){sz=V[a[i]].size()-1;while (sz>=1&&check(V[a[i]][sz-1],V[a[i]][sz])<=check(V[a[i]][sz],i)) V[a[i]].pop_back(),sz--;V[a[i]].PB(i),sz++;while (sz>=1&&getans(V[a[i]][sz-1],i)>=getans(V[a[i]][sz],i)) V[a[i]].pop_back(),sz--;f[i]=getans(V[a[i]][sz],i);}printf("%lld\n",f[n]);return 0;
}

LuoguP5504 [JSOI2011]柠檬相关推荐

  1. bzoj 4709: [Jsoi2011]柠檬(分段DP+决策单调性)

    4709: [Jsoi2011]柠檬 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 240  Solved: 105 [Submit][Status ...

  2. bzoj4709 [Jsoi2011]柠檬

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

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

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

  4. 单调队列优化和决策单调性优化

    前言:dp蒟蒻拼命挽救一下dp a....,会围绕三个"形如"来写...但更重要的是本质理解啊qwq A.单调队列优化: 有时状态转移方程形如f[i][j]=min{f[i-1][ ...

  5. [暑假的bzoj刷水记录]

    (这篇我就不信有网站来扣) 这个暑假打算刷刷题啥的 但是写博客好累啊  堆一起算了 隔一段更新一下.  7月27号之前刷的的就不写了 , 写的累 代码不贴了,可以找我要啊.. 2017.8.27upd ...

  6. 斜率优化dp 的简单入门

    不想写什么详细的讲解了...而且也觉得自己很难写过某大佬(大米饼),于是建议把他的 blog 先看一遍,然后自己加了几道题目以及解析...顺便建议看看算法竞赛(蓝皮书)的 0x5A 斜率优化(P294 ...

  7. LeetCode简单题之柠檬水找零

    题目 在柠檬水摊上,每一杯柠檬水的售价为 5 美元.顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯. 每位顾客只买一杯柠檬水,然后向你付 5 美元.10 美元或 20 美元.你必 ...

  8. 图解:数据结构中的6种「树」,柠檬问你心中有数吗?

    数据结构这门课程是计算机相关专业的基础课,数据结构指的是数据在计算机中的存储.组织方式. 我们在学习数据结构时候,会遇到各种各样的基础数据结构,比如堆栈.队列.数组.链表.树...这些基本的数据结构类 ...

  9. LeetCode 860.柠檬水找零(C++)

    在柠檬水摊上,每一杯柠檬水的售价为 5 美元. 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯. 每位顾客只买一杯柠檬水,然后向你付 5 美元.10 美元或 20 美元.你必须给 ...

最新文章

  1. 学习动力之“学习金字塔 (爱德加•戴尔)”理论
  2. python Elasticsearch 排序
  3. [vue-cli]vue-cli怎么解决跨域的问题?
  4. python数独代码_python 实现计算数独
  5. C/C++小游戏 ——贪吃蛇
  6. idea迁移到其他电脑,省去重新安装破解及配置
  7. Windows Server 2012 MSDN原版 简体中文 版下载
  8. java udp 接收16进制_java UDP通信中十六进制的接收与发送
  9. UCGUI动态内存分析
  10. Materials studio中的简单聚合物的建立及盒子的弛豫
  11. log4j 日志书写格式_Log4J日志配置详解
  12. 如何使用win10自带的录屏工具录制视频
  13. android字体文件制作教程,Android使用自定义字体
  14. 在v$lock里找Holder和Waiter
  15. python爬取头条视频_Python爬虫:爬取某日头条某瓜视频,有/无水印两种方法
  16. 防火墙的访问控制策略
  17. drcom宽带认证登录超时_DrCOM客户端常见问题解决方法
  18. 数据结构:弗洛伊德算法(最短路径)图文详解
  19. 大数据学习的第一课-大数据概论和技术原理
  20. Android 11.0 12.0蓝牙遥控器确认键弹不出输入法的解决方法

热门文章

  1. 数学除了摧残祖国的花朵外,竟然还可以赢钱!
  2. 大变天!刚刚,山东突然宣布!关乎800万人...
  3. 数据库 流量切分_互联网大厂有哪些分库分表的思路和技巧?
  4. 求职华为,被问观察者模式,从没有这种体验!!!
  5. 如何讲页面打入jar包中_如何把我的Java程序变成exe文件?
  6. 计算机网络互联网技术实验报告,2013计算机网络技术与应用.实验报告01
  7. linux安装rz命令_Linux 安装dep安装包命令
  8. circle后面是什么意思 python_Ape circle Python操作-第2-01章-列表操作,小猿圈,作业
  9. java pc计数器_java虚拟机-程序计数器PC Register
  10. 455. 分发饼干001(贪心算法+详解)