Solution -「洛谷 P4372」Out of Sorts P
\(\mathcal{Description}\)
设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排序,则重复冒泡排序零次或多次,直到存在某个位置 \(p\in[l,r)\),满足 \(\max_{i=l}^p\{a_i\}<\min_{i=p+1}^r\{a_i\}\),则递归入 \([l,p]\) 和 \((p,r]\),直到区间长度为 \(1\) 时停止。求所有冒泡排序所操作的区间长度之和。
\(n\le10^5\),保证 \(\{a_n\}\) 无重复数字。
\(\mathcal{Solution}\)
可以发现“递归入两个区间”是对冒泡排序一个并没有什么用的剪枝——两个区间之间一定不会出现元素交换。那么这个剪枝完全可以忽略,算法等价于不停对 \([1,n]\) 冒泡直到序列有序,唯一的区别仅有代价不同。但好处在于,以忽略递归的排序算法为基础,容易求出每个位置什么时候成为分割点 \(p\)——即不停对 \([1,n]\) 冒泡,什么时候 \(\forall a_j\in[1,i],~j\in[1,i]\):这个值就是离 \(i\) 最远的满足 \(a_j\in[1,i]\) 的 \(j\) 到 \(i\) 的距离,倒着扫一遍 BIT 维护即可。
求出每个位置成为分隔点的最早时间 \(t_i\),接下来的做法包括但不限于:
- 按题意模拟!启发式分裂模拟排序算法,\(\mathcal O(n\log n)\);
- 单调栈!扫一遍就行,\(\mathcal O(n)\);
- 算每个点的贡献!排序 \(\max\{t_{i-1},t_{i+1}\}\) 次之后,\(i\) 才会变成长度为 \(1\) 的区间,这就是对答案的贡献,\(\mathcal O(n)\)。
\(\mathcal{Code}\)
按题意模拟好啊,脑细胞多精贵啊。(
注意洛谷原题中,算法会先冒泡一次再检查分割点,细节需要改改。
/*~Rainybunny~*/
#include <bits/stdc++.h>
#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
inline char fgc() {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && ( q = buf + fread( p = buf, 1, 1 << 17, stdin ), p == q )
? EOF : *p++;
}
template<typename Tp = int>
inline Tp rint() {
Tp x = 0; int f = 1; char s = fgc();
for ( ; s < '0' || '9' < s; s = fgc() ) f = s == '-' ? -f : f;
for ( ; '0' <= s && s <= '9'; s = fgc() ) x = x * 10 + ( s ^ '0' );
return x * f;
}
template<typename Tp>
inline void wint( Tp x ) {
if ( x < 0 ) putchar( '-' ), x = -x;
if ( 9 < x ) wint( x / 10 );
putchar( x % 10 ^ '0' );
}
inline void chkmax( int& a, const int b ) { a < b && ( a = b ); }
inline int imin( const int a, const int b ) { return a < b ? a : b; }
const int MAXN = 1e5, MAXLG = 16;
int n, a[MAXN + 5], dc[MAXN + 5], st[MAXN + 5][MAXLG + 5], bitw[MAXN + 5];
long long ans;
struct BIT {
int val[MAXN + 5];
inline void upd( int x, const int v ) {
for ( ; x <= n; x += x & -x ) chkmax( val[x], v );
}
inline int ask( int x ) {
int ret = 0;
for ( ; x; x -= x & -x ) chkmax( ret, val[x] );
return ret;
}
} bit;
inline int qmin( const int l, const int r ) {
int k = bitw[r - l + 1];
return imin( st[l][k], st[r - ( 1 << k ) + 1][k] );
}
inline void solve( const int l, const int r, const int las ) {
if ( l == r ) return ;
int firc = qmin( l, r - 1 ), p = 0;
for ( int len = 0; /* solution always exists */; ++len ) {
if ( st[l + len][0] == firc ) { p = l + len; break; }
if ( st[r - 1 - len][0] == firc ) { p = r - len - 1; break; }
}
ans += ( r - l + 1ll ) * ( firc - las );
solve( l, p, firc ), solve( p + 1, r, firc );
}
int main() {
freopen( "sort.in", "r", stdin );
freopen( "sort.out", "w", stdout );
n = rint();
rep ( i, 1, n ) a[i] = dc[i] = rint();
std::sort( dc + 1, dc + n + 1 ); // no need to unique.
// assert( std::unique( dc + 1, dc + n + 1 ) - dc - 1 == n );
rep ( i, 1, n ) a[i] = std::lower_bound( dc + 1, dc + n + 1, a[i] ) - dc;
bit.upd( a[n], n );
per ( i, n - 1, 1 ) {
if ( ( st[i][0] = bit.ask( i ) ) ) st[i][0] -= i;
bit.upd( a[i], i );
}
rep ( i, 2, n ) bitw[i] = bitw[i >> 1] + 1;
for ( int j = 1; 1 << j <= n; ++j ) {
rep ( i, 1, n - ( 1 << j ) + 1 ) {
st[i][j] = imin( st[i][j - 1], st[i + ( 1 << j >> 1 )][j - 1] );
}
}
solve( 1, n, 0 );
wint( ans ), putchar( '\n' );
return 0;
}
Solution -「洛谷 P4372」Out of Sorts P的更多相关文章
- Note/Solution -「洛谷 P5158」「模板」多项式快速插值
\(\mathcal{Description}\) Link. 给定 \(n\) 个点 \((x_i,y_i)\),求一个不超过 \(n-1\) 次的多项式 \(f(x)\),使得 \(f(x ...
- Solution -「洛谷 P4198」楼房重建
\(\mathcal{Description}\) Link. 给定点集 \(\{P_n\}\),\(P_i=(i,h_i)\),\(m\) 次修改,每次修改某个 \(h_i\),在每次修改后 ...
- Solution -「洛谷 P6577」「模板」二分图最大权完美匹配
\(\mathcal{Description}\) Link. 给定二分图 \(G=(V=X\cup Y,E)\),\(|X|=|Y|=n\),边 \((u,v)\in E\) 有权 \(w( ...
- Solution -「洛谷 P6021」洪水
\(\mathcal{Description}\) Link. 给定一棵 \(n\) 个点的带点权树,删除 \(u\) 点的代价是该点点权 \(a_u\).\(m\) 次操作: 修改单点点权. ...
- Solution -「洛谷 P4719」「模板」"动态 DP" & 动态树分治
\(\mathcal{Description}\) Link. 给定一棵 \(n\) 个结点的带权树,\(m\) 次单点点权修改,求出每次修改后的带权最大独立集. \(n,m\le10^5 ...
- Solution -「洛谷 P5236」「模板」静态仙人掌
\(\mathcal{Description}\) Link. 给定一个 \(n\) 个点 \(m\) 条边的仙人掌,\(q\) 组询问两点最短路. \(n,q\le10^4\),\(m\ ...
- Solution -「洛谷 P4320」道路相遇
\(\mathcal{Description}\) Link. 给定一个 \(n\) 个点 \(m\) 条边的连通无向图,并给出 \(q\) 个点对 \((u,v)\),询问 \(u\) 到 ...
- Solution -「洛谷 P5827」边双连通图计数
\(\mathcal{Description}\) link. 求包含 \(n\) 个点的边双连通图的个数. \(n\le10^5\). \(\mathcal{Solution}\) ...
- Solution -「洛谷 P5827」点双连通图计数
\(\mathcal{Description}\) link. 求有 \(n\) 个结点的点双连通图的个数,对 \(998244353\) 取模. \(n\le10^5\). \(\mat ...
随机推荐
- android studio 配置 Lombok 插件 -具体步骤
1.前言 idea 用惯了 Lombok 插件了,好用的很,可是开发安卓 却没有,即便在 android studio 安装了插件,但是仍然无法使用 因为需要配置 2.解决 (1)进入设置,找到插件设 ...
- vert.x框架与tomcat的关系
1.前言 大学4年,老师唯一让我们学习的web服务器是tomcat,配置方式是先从官网下载阿帕奇的tomcat文件,然后在开发平台导入,然后再配置web.xml等文件, 是一个可同步可异步请求的服务器 ...
- win11系统设置笔记本合盖上不休眠
第一步.打开控制面板 第二步.打开控制面板 第三步.打开电源选项 第四步.如下图操作即可
- PPT制作手机滑动粗糙效果
原文链接:https://www.toutiao.com/i6495291974680052238/ 选择"插入"选项卡,"插图"功能组."形状&qu ...
- SYCOJ2100摆动序列
题目-摆动序列 (shiyancang.cn) 直接分成两部分,插入即可.只有一个地方不对,那就是符号.两个大的放一个小的,两个小的放一个大的.那么每次的大的放最大的,每次的小的放其次小的,用完就不用 ...
- 关于Jmeter线程数Ramp-Up.循环次数的理解和实验数据
1. 关于线程组参数 线程组:即一个线程组实例里面包括多个串行的请求或动作.一个线程组的从启动到结束的时间取决于你线程中的步骤数量. 线程数:即用户数,在Ramp-up时间内(包括循环),简单把线程数 ...
- Natasha 4.0 探索之路系列(二) "域"与插件
域与ALC 在 Natasha 发布之后有不少小伙伴跑过来问域相关的问题, 能不能兼容 AppDomain, 如何使用 AppDomain, 为什么 CoreAPI 阉割了 AppDomain 等一系 ...
- Android系统编程入门系列之硬件交互——通信硬件NFC
在上篇文章介绍了接入式USB硬件的简单使用,接下来将介绍不依赖物理连接的硬件通信了.本文的重点是近距离通信的硬件NFC. NFC硬件 应用程序中可以通过NFC硬件读取或发送指定协议的技术实现,在And ...
- xargs、管道、exec区别
作者:ilexwg链接:https://www.zhihu.com/question/27452459/answer/170834758来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转 ...
- mybatis配置入门中遇到的问题
问题一 非法注射 问题描述:WARNING: An illegal reflective access operation has occurred 这种问题主要是jdk版本和mybatis的jar包 ...