CF1455D 序列和交换

1 CF1455D 序列和交换

2 题目概要:

给定一个序列 \(𝑎\)\(𝑛\) 个整数 \(𝑎1,𝑎2,...,𝑎𝑛\) 和一个整数 \(𝑥\) 组成。对 \(𝑎\) 进行升序排序, 如果 \(𝑎_1≤𝑎_2≤𝑎_3≤⋯≤𝑎_𝑛\) 成立,则称之为有序。

要对序列进行排序,可以执行任意次数的以下操作(也有可能零次):选择一个整数 \(𝑖\) 使 \(1≤𝑖≤𝑛\) 同时 \(𝑎_𝑖>𝑥\),交换 \(𝑎_𝑖\)\(𝑥\) 的值。

例如,如果 \(𝑎=[0,2,3,5,4]\), \(x=1\), 下列操作顺序是可能的:

  1. 选择 \(𝑖=2\)(有可能因为 \(𝑎_2>𝑥\)),所以 \(𝑎=[0,1,3,5,4]\), \(𝑥=2\);

  2. 选择 \(𝑖=3\)(有可能因为 \(𝑎_3>𝑥\)),所以 \(𝑎=[0,1,2,5,4]\), \(𝑥=3\);

  3. 选择 \(𝑖=4\)(有可能因为 \(𝑎_4>𝑥\)),所以 \(𝑎=[0,1,2,3,4]\), \(𝑥=5\)

    计算对 \(𝑎\) 进行排序需要的最少操作次数或者输出不可能。

3 解题思路

这道题是一道明显的数学题。分析性质,发现:如果序列中的某个数比 \(x\) 小且比它前面的那个数小(即无序),那么无论我们如何交换,都无法将该序列改为递增序列。由于与 \(x\) 交换的数必须比 \(x\) 要大,所以 \(x\) 在每次交换完成后必将变大。所以当前 \(k\) 个数已经变成有序数列且前 \(k\) 个数都小于等于 \(x\),后面的数都大于 \(x\) 时,我们必须将第 \(k+1\) 个数与 \(x\) 交换。否则,如果我们先跟后面的数交换,那么后面的数必定小于第 \(k+1\) 个数。根据性质,该数列无法成为递增序列。如果不满足前 \(k\) 个数为有序数列,前 \(k\) 个数都比 \(x\) 小,后面的数都大于 \(x\) 其中的任意一条,那么也无法成为递增序列。

由此,我们可以推出本题做法:每一次操作,将\(x\)与当前的第一个数交换,答案 \(+1\),然后判断小于等于交换后的 \(x\) 的数组成的数列是否递增。若不是递增,则无法变成递增数列。若为递增,则抹去这些数。每次操作结束后都判断整个序列是否变成了递增序列,如果变成了递增序列,就输出答案。

4 代码实现

代码(空格警告):

#include <iostream>
using namespace std;
const int N = 505;
int T, n, x, head, flag, cnt;
int a[N];
void update()
{
    while (head <= n)
    {
        if (a[head] > x) break;
        if (a[head] < a[head-1])
        {
            flag = 1;
            break;
        }
        head++;
    }
}
int main()
{
    cin >> T;
    while (T--)
    {
        cin >> n >> x;
        for (int i = 1; i <= n; i++) cin >> a[i];
        head = 1, flag = 1, cnt = 0;
        for (int i = 1; i <= n; i++) if (a[i] < a[i-1]) flag = 0;
        if (flag)
        {
            cout << 0 << endl;
            continue;
        }
        update();
        if (flag)
        {
            cout << -1 << endl;
            continue;
        }
        while (head <= n)
        {
            swap(a[head], x);
            update();
            if (flag)
            {
                cout << -1 << endl;
                break;
            }
            cnt++;
            flag = 1;
            for (int i = 1; i <= n; i++) if (a[i] < a[i-1]) flag = 0;
            if (flag)
            {
                cout << cnt << endl;
                break;
            }
        }
    }
    return 0;
}

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

posted @ 2021-02-04 23:10  David24  阅读(101)  评论(0编辑  收藏  举报