洛谷 P7714 排列排序
1 P7714 排列排序
2 题目描述
时间限制 \(1s\) | 空间限制 \(128M\)
小 \(E\) 给你一个长度为 \(n\) 的排列 \(p_1,p_2, \cdots ,p_n\)。小 \(E\) 想要把它排序。
小 \(E\) 每次可以花区间长度,即 \(r-l+1\) 的代价,选择排列中的任意一段区间 \([l,r]\),并将 \([l,r]\) 从小到大排序。
现在你可以让他进行若干次这个操作,直到 \(p\) 中元素的值从 \(1\) 到 \(n\) 按升序排序,即对于 \(1\) 到 \(n\) 的每一个 \(i\),都有 \(p_i=i\)。
小 \(E\) 问你,他花的代价最少为多少?
数据范围:\(1≤T,∑n≤10^6\)
3 题解
我们发现:有一些在正确位置的数不需要被排序。那么具体是哪些呢?
我们可以考虑将每个在正确位置的数看成分界点。如果数组的开头与当前分界点之间的数恰好对应的是 \(1\) 到当前分界点之间的数,只不过顺序不同,那么我们就可以不把这个分界点计入答案中。
我们如何检查数组的开头与当前分解点之间的数是否恰好对应的是 \(1\) 到当前分界点之间的数呢?我们发现,由于数组是 \(1\) 到 \(n\) 之间的排列,所以每一个数都只出现了一次。也就是说,如果当前数开头到分界点之间的最大值等于分界点,那么这一段就一定是某段排列。
4 代码(空格警告):
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1e6 + 10;
int n, maxn, T, cnt;
int a[N];
int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return x * f;
}
int main()
{
T = read();
while (T--)
{
maxn = 0, cnt = 0;
n = read();
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1; i <= n; i++)
{
maxn = max(a[i], maxn);
if (a[i] == i && i == maxn) cnt++;
}
printf("%d\n", n - cnt);
}
return 0;
}