NOI.AC[32] 排序

题面

题解

首先离散化

考虑如何翻转

用快排的方式可以将区间划分成两段$[l,\;mid],\;[mid+1,\;r]$

可以将这一段序列转化成$01$序列

$<=mid$的为$0$, $>mid$的为$1$

对于这个序列进行归并排序

具体来说, 归并前的序列为一个

[l, mid] [mid + 1, r]
0000…01111 00001…1111

那么将中间的$11110000$翻转即可

时间复杂度$O(nlog^2n)$

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include<bits/stdc++.h>
#define RG register
#define clear(x, y) memset(x, y, sizeof(x));
using namespace std;

inline int read()
{
int data=0, w=1;
char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1, ch=getchar();
while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+(ch^48), ch=getchar();
return data*w;
}

const int maxn(50010);
int n, a[maxn], b[maxn], c[maxn];
vector<pair<int, int> > ans;

void merge(int l, int r)
{
if(l == r) return;
int mid(l + r >> 1);
merge(l, mid); merge(mid + 1, r);
int pos_1 = mid + 1, pos_0 = mid;
for(RG int i=l;i<=mid;i++) if(c[i] == 1) { pos_1 = i; break; }
for(RG int i=r;i>mid;i--) if(c[i] == 0) { pos_0 = i; break; }
if(pos_1 == mid + 1 || pos_0 == mid) return;
reverse(c + pos_1, c + pos_0 + 1);
reverse(a + pos_1, a + pos_0 + 1);
ans.push_back(make_pair(pos_1, pos_0));
}

void Div(int l, int r)
{
if(l == r) return;
int mid(l + r >> 1);
for(RG int i=l;i<=r;i++) c[i] = a[i] <= mid ? 0 : 1;
merge(l, r);
Div(l, mid); Div(mid+1, r);
}

inline int cmp(const int &x, const int &y) { return a[x] < a[y]; }
int main()
{
n = read();
for(RG int i=1;i<=n;i++) a[i] = read(), b[i] = i;
sort(b + 1, b + n + 1, cmp);
for(RG int i=1;i<=n;i++) a[b[i]] = i;
Div(1, n);
for(RG vector<pair<int, int> >::iterator it = ans.begin(); it != ans.end(); ++it)
printf("%d %d\n", it->first, it->second);
puts("-1 -1");
return 0;
}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×