LuoguP7852 「EZEC-9」Yet Another Easy Problem 题解

Content

给定 \(n,m\),你需要输出一个长度为 \(n\) 的排列,满足该排列进行不超过 \(m\) 次交换操作可以得到的最小的字典序最大。

数据范围:\(T\) 组数据,\(1\leqslant T\leqslant 10^5\),\(1\leqslant n\leqslant 10^5\),\(\sum n\leqslant 10^5\),\(0\leqslant m\leqslant n\)。

Solution

算是一道比较小清新的构造题,接下来教你如何弄出正确的构造方案。

首先,要如何分配这 \(m\) 次交换,使得 \(m\) 次交换后的数列字典序最小?经分析不难得知,第 \(i\) 次交换的时候就应该把数字 \(i\) 和第 \(i\) 个位置上的数字进行交换,才能够达到最小字典序的目的。

那么如何构造出数列使得 \(m\) 次交换后的数列的最小字典序最大?既然 \(m\) 次交换后前面交换完的数已经是字典序最小了,那么就应当使得后面的部分的字典序最大。同时,为了尽可能多地消耗交换次数,不应该将数字 \(i(1\leqslant i\leqslant m)\) 放在第 \(i\) 个位置上面。

那么构造方案就呼之欲出了:\(\{n,1,2,\dots,m,n-1,n-2,\dots,m+1\}\)。这样构造既可以保证前 \(m\) 个要交换的数字不在自己的数字所表示的位置上面,又可以在 \(m\) 次交换之后使得最小字典序最大。因为后面的数不用进行交换,我们就先按照字典序最大给它排列好了,这样交换完以后后面的 \(n-m\) 个数字就一定可以保证是字典序最大的(前 \(m\) 个数字已经确定是 \(1,2,\dots,m\) 了)。

Code

namespace Solution {
    const int N = 1e5 + 7;
    int n, m;

    iv Main() {
        MT {
            read(n, m);
            if(n == m) F(int, i, 1, n) printf("%d%c", i, " \n"[i == n]);
            else {
                printf("%d", n);
                F(int, i, 1, m) printf(" %d", i);
                R(int, i, n - 1, m + 1) printf(" %d", i);
                puts("");
            }
        }
        return;
    }
}
上一篇:Centos7.X安装impala(RPM方式)


下一篇:Java反射获取字段的属性值及对比两个对象的属性值null差异赋值,递归算法查找