洛谷 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;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-07-12 22:33  David24  阅读(188)  评论(0编辑  收藏  举报