CF1827B2 Range Sorting (Hard Version) 题解
*CF1827B2 Range Sorting (Hard Version)
一.思路:
按题意去找似乎很麻烦。但是注意到,我们若对每个区间都暴力的花费\(r-l\)的代价去修改所有区间,总代价为
\]
这就提醒我们反向来思考,发现我们如果将一段区间拆成两段处理,并且依旧可以变得有序,代价会少\(1\),而且两次操作区间与区间之间不相交一定最优,所以我们的目标就是要找到所有可以这样拆开的区间来减少我们花费的代价。可以证明的是,满足这样的条件的区间需要满足的充要条件是:
\]
即前半段最大值小于后半段最小值。
我们发现直接模拟这个性质复杂度属于是直接爆了,所以换个思路,我们假定某一个位置\(i\),\(a_i\)是某个右半区间\([x,r]\)的最小值,那么\([l,x-1]\)的最大值要小于\(a_i\)
现在也就需要统计有多少区间\([l,r]\)可以拆成两半,并且一定有\(i\in[x,r]\)
那么我们找到\(i\)后面第一个比\(i\)小的数\(a_{minr}\),所以\(r\)可以是区间\([x,minr)\)中的任意整数。接着我们找到\(i\)前面第一个比\(a_i\)小的数\(a_{tmin}\),根据定义,这个数只能放在左半边区间,且作为左右区间分界点,也就是下标\(tmin=x-1\)。最后,从\(tmin\)往前找第一个比\(a_i\)大的数\(a_{maxl}\),所以\(l\)可以是区间\((maxl,tmin]\)中的任意一个数。
因为每拆一次少\(1\)的代价,所以最后来自这些区间的贡献就为:
\]
现在有一个关键问题:如何快速处理找前后的第一个\(\max/\min\)呢?其实处理方式有很多,这里说一下我个人的方法:相信找数这个问题我们都不陌生,很容易想到二分查找,但是问题在于这道题的序列是无序的,没有单调性,所以我们理应要去构造一些新东西来给二分check。可能没什么头绪,那我们不妨从头思考,为什么我们的复杂度高呢?显然的,这是因为我们每一次都要去扫描前面的数然后去打擂台处理,我们希望有一种办法可以快速高效的查询一段区间的最值,所以第一反应是线段树或者树状数组,事实上,这是可行的,但是别忘了,我们的序列是静态的,我们有更加快速的查询方法,即:我会ST表!我们尝试着将ST表与二分进行结合,每一次查询起始点到\(mid\)之间d的最值,结合当前的\(a_i\)的大小对数级别复杂度缩小每一次的查询范围,最后得到结果
二.code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
inline LL read() {
int x=0,f=1;char ch=getchar();
while(ch > '9' || ch < '0'){if(ch == '-'){f = -1;}ch = getchar();}
while(ch >= '0'&&ch <= '9'){x = x * 10 + ch - 48; ch = getchar();}
return x * f;
}
const int N = 1e6 + 10;
const int LOg_2 = 20;
LL n,ans;
int perm[N],st_min[N][LOg_2],st_max[N][LOg_2];
int l2[N];
void init()
{
int lim = l2[n];
for(int j = 1;j <= lim;++j)
{
int add_up = (1 << j) - 1,add_up2 = (1 << (j - 1));
for(int i = 1;i + add_up - 1 <= n;++i)
{
st_min[i][j] = std::min(st_min[i][j - 1],st_min[i + add_up2][j - 1]);
st_max[i][j] = std::max(st_max[i][j - 1],st_max[i + add_up2][j - 1]);
}
}
}
int query_min(int l,int r)
{
int k = l2[r - l + 1];
return std::min(st_min[l][k],st_min[r - (1 << k) + 1][k]);
}
int query_max(int l,int r)
{
int k = l2[r - l + 1];
return std::max(st_max[l][k],st_max[r - (1 << k) + 1][k]);
}
int main()
{
n = read();
for(int i = 1;i <= n;++i)
{
perm[i] = read();
st_min[i][0] = st_max[i][0] = perm[i];
}
ans = (n * (n + 1) / 2) * (n - 1) / 3;
l2[0] = -1;
for(int i = 1;i <= n;++i) l2[i] = l2[i >> 1] + 1;
init();
for(int i = 1;i <= n;++i)
{
int ll = 0,rl = 0,rr = n + 1;
int l = i + 1,r = n;
while(l <= r)
{
int mid = (l + r) >> 1;
if(query_min(i + 1,mid) < perm[i])
r = mid - 1,rr = mid;
else
l = mid + 1;
}
l = 1,r = i - 1;
while(l <= r)
{
int mid = (l + r) >> 1;
if(query_min(mid,i - 1) < perm[i])
l = mid + 1,rl = gmid;
else
r = mid - 1;
}
l = 1,r = rl - 1;
while(l <= r)
{
int mid = (l + r) >> 1;
if(query_max(mid,rl - 1) > perm[i])
l = mid + 1,ll = mid;
else
r = mid - 1;
}
ans -= 1ll * (rr - i) * (rl - ll);
}
std::cout << ans;
return 0;
}
CF1827B2 Range Sorting (Hard Version) 题解的更多相关文章
- Codeforces 258D Little Elephant and Broken Sorting (看题解) 概率dp
Little Elephant and Broken Sorting 怎么感觉这个状态好难想到啊.. dp[ i ][ j ]表示第 i 个数字比第 j 个数字大的概率.转移好像比较显然. #incl ...
- Codeforces 1196D2 RGB Substring (Hard version) 题解
题面 \(q\) 个询问,每个询问给出一个字符串 \(s\),要你在 \(s\) 中用最小替换得到无穷字符串 RGBRGBRGB... 的长度为定值 \(k\) 的子串. 题解 一眼看过去可能是编辑距 ...
- [LeetCode] Range Sum Query - Mutable 题解
题目 题目 思路 一看就是单点更新和区间求和,故用线段树做. 一开始没搞清楚,题目给定的i是从0开始还是从1开始,还以为是从1开始,导致后面把下标都改掉了,还有用区间更新的代码去实现单点更新,虽然两者 ...
- CF1157C1-Increasing Subsequence (easy version)题解
原题地址 题目大意:
- Hdoj 2501.Tiling_easy version 题解
Problem Description 有一个大小是 2 x n 的网格,现在需要用2种规格的骨牌铺满,骨牌规格分别是 2 x 1 和 2 x 2,请计算一共有多少种铺设的方法. Input 输入的第 ...
- Palindromes _easy version 题解
“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串.请写一个程序判断读入的字符串是否是“回文”. Input输入包含多个测试实例,输入数据的第一行是一个正整数n ...
- CF1203D2 Remove the Substring (hard version) 题解
这题初赛让我白给了6分,于是我决定回来解决一下它. 说实话,看原题题面和看CCF代码真是两种完全不同的感受…… ------------思路分析: 把$s$串删去一部分之后,会把$s$串分成两部分,当 ...
- CF605A Sorting Railway Cars 题解
To CF 这道题依题意可得最终答案为序列长度-最长子序列长度. 数据范围至 \(100000\) 用 \(O(n^2)\) 的复杂度肯定会炸. 用 \(O(nlogn)\) 的复杂度却在第 \(21 ...
- UVA12558 Egyptian Fractions (HARD version) (埃及分数,迭代加深搜索)
UVA12558 Egyptian Fractions (HARD version) 题解 迭代加深搜索,适用于无上界的搜索.每次在一个限定范围中搜索,如果无解再进一步扩大查找范围. 本题中没有分数个 ...
- [Leetcode Week16]Range Sum Query - Mutable
Range Sum Query - Mutable 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/range-sum-query-mutable/de ...
随机推荐
- 【译】Visual Studio 2022 v17.14 现已正式发布!
我们很高兴地宣布 Visual Studio 2022 17.14 正式发布!此版本延续了我们的使命--为开发者提供更快.更智能且更高效的工具,以应对各种开发工作. 在这个版本中有很多开发者喜欢的东西 ...
- RBMQ与odoo15的集成
背景:在对接物联网设备时候常用的协议就是:MQTT.AMQ.https.还有WebSocket,此案例就是针对接物联网设备传输的消息的消费 原理:通过新建守护线程的方式来启动mq服务,来消费设备平台端 ...
- Java 把列表元素拼接字符串
摘要:使用 Java Collectors.joining等方法把List中的所有元素通过指定的分隔符拼接为字符串. 目录 综述 使用For循环 StringUtils.join 函数 Collect ...
- mysql安装配置启动
1. 安装 & 配置 & 启动 MySQL现在的版本主要分为: 5.x 版本,现在互联网企业中的主流版本,包括:头条.美图.百度.腾讯等互联网公司主流的版本. 8.x 版本,新增了一些 ...
- linux下wget静默模式下载
说明 在一些场景下,文件较大时,通过wget下载会展示时候进度,输出太多,这里我们如果想屏蔽输出可以采取静默模式 wget --quiet http://fileserver.test.com/cud ...
- vue.js+vuetify学习开发排坑:一个古怪的代码 v-slot:activator="{ on, attrs }"
由于需要全栈开发一个售票系统项目,时隔一年后重新捡回了我的前端技术~ 开发习惯是边看文档边做,然后再vuetify这个MD设计的UI元件库翻来翻去,再涉及到元件交互的时候有几段代码不是很能理解 < ...
- hbuilderx打包ios应用和上传应用商店最简单方法
hbuilderx是一个跨平台的开发软件,一般的软件公司,电脑使用的是windows系统. 那么windows有没有办法开发ios应用呢,因为ios的证书和上传,好像都需要mac电脑来完成. 其实,国 ...
- 在线人民币大小写转换工具html代码
该工具旨在帮助用户方便地将人民币金额从小写转换为大写,只需输入金额,点击转换按钮,即可快速获得准确的大写表示.工具界面简洁友好,支持输入各种格式的大写金额,如"1356.78元". ...
- 从 TCP 到 WebSocket:一次搞懂网络通信的三层演进
引言 在现代应用开发中,网络通信是绕不开的核心议题.无论是构建传统的 Web 应用,还是开发需要实时交互的系统(如在线协作工具.金融行情推送.多人游戏),我们总会与 TCP.HTTP.WebSocke ...
- 别再被 Spring Security 和 Shiro 劝退了!这款国产 Java 权限框架真香!
Hello,大家好,我是程序员NEO. 在 Java 开发中,权限认证是个绕不开的话题.但一提起 Spring Security 或 Shiro,很多人是不是瞬间就头大了?复杂的配置.陡峭的学习曲线, ...