P8500 [NOI2022] 冒泡排序

探讨了在满足特定条件的序列中,如何通过冒泡排序实现最少交换次数的问题,涉及编程技巧和算法优化。
摘要由CSDN通过智能技术生成

题目背景

最近,小 Z 对冒泡排序产生了浓厚的兴趣。

下面是冒泡排序的伪代码:

输入: 一个长度为 n 的序列 a[1...n]
输出: a 从小到大排序后的结果
for i = 1 to n do:
    for j = 1 to n - 1 do
        if (a[j] > a[j + 1])
            交换 a[j] 与 a[j + 1] 的值

冒泡排序的交换次数被定义为在排序时进行交换的次数,也就是上面冒泡排序伪代码第六行的执行次数。他希望找到一个交换次数尽量少的序列。

题目描述

小 Z 所研究的序列均由非负整数构成。它的长度为 nn,且必须满足 mm 个附加条件。其中第 ii 个条件为:下标在 [L_i, R_i][Li​,Ri​] 中的数,即 a_{L_i}, a_{L_{i+1}},\dots,a_{R_i}aLi​​,aLi+1​​,…,aRi​​ 这些数,其最小值恰好为 \boldsymbol{V_i}Vi​

他知道冒泡排序时常会超时。所以,他想要知道,在所有满足附加条件的序列中,进行冒泡排序的交换次数的最少值是多少。

输入格式

本题有多组数据。

输入的第一行包含一个正整数 TT。

对于每组数据,第一行包含两个正整数 n,mn,m。数据保证 1 \leq n,m \leq 10^61≤n,m≤106。

接下来 mm 行,每行三个非负整数 L_i, R_i, V_iLi​,Ri​,Vi​,表示一组附加条件。数据保证 1 \leq L_i \leq R_i \leq n1≤Li​≤Ri​≤n、0 \leq V_i \leq 10^90≤Vi​≤109。

输出格式

输出共 TT 行,每行一个整数。

对于每组数据,如果存在满足这 mm 个附加条件的序列,则输出在所有满足附加条件的序列中,冒泡排序交换次数的最小值。如果不存在满足所有条件的序列,则输出 -1−1。

输入输出样例

输入 #1复制

1
3 2
1 1 2022
2 3 39

输出 #1复制

1

说明/提示

【样例解释 #1】

这组数据的约束条件为 a_1 = 2022, \min\{a_2, a_3\} = 39a1​=2022,min{a2​,a3​}=39。

若 a_2 = 39a2​=39,且 39 \leq a_3 < 202239≤a3​<2022,则冒泡排序只有第一轮有交换操作,这一轮交换了 a_1, a_2a1​,a2​ 和 a_2, a_3a2​,a3​,总交换次数为 22。

若 a_2 = 39a2​=39,且 a_3 \geq 2022a3​≥2022,则冒泡排序只有第一轮有交换操作,这一轮仅仅交换 a_1, a_2a1​,a2​,总交换次数为 11。

若 a_3 = 39a3​=39,且 39 < a_2 < 202239<a2​<2022,则冒泡排序算法第一轮交换 a_1, a_2a1​,a2​ 和 a_2, a_3a2​,a3​,第二轮交换 a_1, a_2a1​,a2​。总交换次数为 33。

若 a_3 = 39a3​=39,且 a_2 \geq 2022a2​≥2022,则冒泡排序算法第一轮交换 a_2, a_3a2​,a3​,第二轮交换 a_1, a_2a1​,a2​。总交换次数为 22。

因此,交换次数的最小值为 11。


【样例 #2】

见附件中的 bubble/bubble2.in 与 bubble/bubble2.ans


【样例 #3】

见附件中的 bubble/bubble3.in 与 bubble/bubble3.ans

这个样例满足测试点 8 \sim 108∼10 的条件。


【样例 #4】

见附件中的 bubble/bubble4.in 与 bubble/bubble4.ans

这个样例满足测试点 13 \sim 1413∼14 的条件。


【样例 #5】

见附件中的 bubble/bubble5.in 与 bubble/bubble5.ans

这个样例满足测试点 15 \sim 1615∼16 的条件。


【样例 #6】

见附件中的 bubble/bubble6.in 与 bubble/bubble6.ans

这个样例满足测试点 23 \sim 2523∼25 的条件。


【数据范围】

本题共 2525 个测试点。全部测试点满足:1 \leq T \leq 10001≤T≤1000,1 \leq \sum n, \sum m \leq 10^61≤∑n,∑m≤106,1 \leq L_i \leq R_i \leq n1≤Li​≤Ri​≤n,0 \leq V_i \leq 10^90≤Vi​≤109。

其中 \sum n, \sum m∑n,∑m 分别表示所有测试点的 nn 的总和和 mm 的总和。\sum n^2, \sum m^2, \sum n^3, \sum m^3∑n2,∑m2,∑n3,∑m3 的含义类似。

测试点数据范围特殊性质
1 \sim 41∼4n,m \leq 7n,m≤7,且最多 22 组数据不满足 n, m \leq 5n,m≤5
5 \sim 75∼7n,m \leq 17n,m≤17,且最多 33 组数据不满足 n, m \leq 9n,m≤9A
8 \sim 108∼10n,m \leq 100n,m≤100,\sum n^3,\sum m^3 \leq 4 \times 10^7∑n3,∑m3≤4×107A
11 \sim 1211∼12n,m \leq 2000n,m≤2000,\sum n^2,\sum m^2 \leq 4 \times 10^7∑n2,∑m2≤4×107A
13 \sim 1413∼14n,m \leq 2000n,m≤2000,\sum n^2,\sum m^2 \leq 4 \times 10^7∑n2,∑m2≤4×107B
15 \sim 1615∼16n,m \leq 2000n,m≤2000,\sum n^2,\sum m^2 \leq 4 \times 10^7∑n2,∑m2≤4×107C
17 \sim 1817∼18n,m \leq 2000n,m≤2000,\sum n^2,\sum m^2 \leq 4 \times 10^7∑n2,∑m2≤4×107
1919\sum n,\sum m \leq 10^6∑n,∑m≤106A
2020\sum n,\sum m \leq 10^6∑n,∑m≤106B
21 \sim 2221∼22\sum n,\sum m \leq 10^6∑n,∑m≤106C
23 \sim 2523∼25\sum n,\sum m \leq 10^6∑n,∑m≤106

特殊性质 A:对于 1 \leq i \leq m1≤i≤m,0 \leq V_i \leq 10≤Vi​≤1。
特殊性质 B:对于 1 \leq i \leq m1≤i≤m,L_i = R_iLi​=Ri​。
特殊性质 C:输入给出的 mm 个区间 [L_i, R_i][Li​,Ri​] 两两不相交。


【提示】

本题的部分测试点输入量较大。我们建议你使用较为快速的读入方式。

附件下载

bubble.zip6.95MB

看之前先看提示:本题难度为NOI/NOI+/CTSC,先了解思路再来

AC代码:

#include<bits/stdc++.h>
#define re register
using namespace std;
inline int read(){
	re int t=0;re char v=getchar();
	while(v<'0')v=getchar();
	while(v>='0')t=(t<<3)+(t<<1)+v-48,v=getchar();
	return t;
}
int t,n,m,a[1000002],A,B,L[1000002],R[1000002],V[1000002],W[1000002],mn[4000002],mnp[4000002],tg[4000002],fa[1000002],V1[1000002],V2[1000002],c[1000002],ans1,ans2;
char s[1000002];
inline void add(re int x){for(;x;x^=x&(-x))++c[x];}
inline int ask(re int x,re int s=0){for(;x<=m;x+=x&(-x))s+=c[x];return s;} 
inline void build(re int p,re int l,re int r){
	tg[p]=mn[p]=0,mnp[p]=l;
	if(l==r)return;
	re int mid=l+r>>1;
	build(p<<1,l,mid),build(p<<1|1,mid+1,r); 
}
inline void pu(re int p){
	mn[p]=min(mn[p<<1],mn[p<<1|1]);
	if(mn[p]==mn[p<<1])mnp[p]=mnp[p<<1];
	else mnp[p]=mnp[p<<1|1];
}
inline void Add(re int x,re int y){mn[x]+=y,tg[x]+=y;}
inline void pd(re int p){
	if(tg[p])Add(p<<1,tg[p]),Add(p<<1|1,tg[p]),tg[p]=0;
}
inline void add(re int p,re int l,re int r,re int x,re int y,re int z){
	if(l>=x&&r<=y)return Add(p,z);
	pd(p);
	re int mid=l+r>>1;
	if(x<=mid)add(p<<1,l,mid,x,y,z);
	if(y>mid)add(p<<1|1,mid+1,r,x,y,z);
	pu(p);
}
inline void ask(re int p,re int l,re int r,re int x,re int y){
	if(l>=x&&r<=y){
		if(mn[p]<ans2)ans2=mn[p],ans1=mnp[p];
		return;
	}pd(p);
	re int mid=l+r>>1;
	if(x<=mid)ask(p<<1,l,mid,x,y);
	if(y>mid)ask(p<<1|1,mid+1,r,x,y);
}
struct node{int x,y;bool operator <(const node A)const{return x<A.x;};};
inline int root(re int x){return x==fa[x]?x:fa[x]=root(fa[x]);}
vector<node>G[1000002];
int main(){
	t=read();
	while(t--){
		n=read(),m=read();
		for(re int i=1;i<=m;++i)L[i]=read(),R[i]=read(),V[i]=W[i]=read(),G[i].clear();
		for(re int i=1;i<=n;++i)V1[i]=V2[i]=0; 
		sort(W+1,W+m+1);
		for(re int i=1;i<=m;++i)V[i]=lower_bound(W+1,W+m+1,V[i])-W,G[V[i]].push_back((node){L[i],R[i]});
		for(re int i=1;i<=n+1;++i)fa[i]=i;re bool ia=1;
		for(re int i=m;i&&ia;--i)if(G[i].size()){
			sort(G[i].begin(),G[i].end());
			re int lst=n+1; 
			for(re int j=G[i].size()-1;~j&&ia;--j)
				if(G[i][j].y<lst){
					re int pos=root(G[i][j].x);
					V1[pos]=i,ia&=pos<=G[i][j].y,lst=pos;
				}
			for(auto z:G[i])
			for(re int j=root(z.x);j<=z.y;j=root(j))V2[j]=i,fa[j]=j+1;
		}if(!ia){puts("-1");continue;}build(1,0,m+1);long long ans=0;
		for(re int i=1;i<=m;++i)c[i]=0;
		for(re int i=1;i<=n;++i)if(V1[i])ans+=ask(V1[i]+1),add(V1[i]),add(1,0,m+1,V1[i]+1,m+1,1);
		for(re int i=1;i<=n;++i)
			if(V1[i])add(1,0,m+1,V1[i]+1,m+1,-1),add(1,0,m+1,0,V1[i]-1,1);
			else{
				ans2=1e9,ask(1,0,m+1,V2[i],m+1);
				ans+=ans2;
				if(ans1)add(1,0,m+1,0,ans1-1,1);
			}
		printf("%lld\n",ans);
	}
}

给个关注吧~~~

  • 38
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值