Minimize Permutation Subarrays
题意
本题要求从数组中任选两个数交换一次,使得数组中所有子段中排列的数量最少。
其中,排列指长度为 的数组包含 所有元素。
解析
首先, 本身就是一个排列,原数组本身也是一个排列,这都是无法改变的。
那么,对于剩下的排列,其中必须包含 。我们只需要让 和 之间的距离尽可能的远就可以了。夸张一下, 在最左端, 在最右端,那么所有的子串(除了 和原数组本身)都会因为少 或少 而导致无法组成排列。
可惜题目指允许交换一次,这种情况不一定能实现,但我们仍然可以往这条路上想。
除了 以外的排列,都必须包含 和 ,同时不能包含比该数组长度大的数。因此,我们将一个大数 放在 和 中间,这样一个子串若同时包含 和 ,就也包含这个 了。这种时候,除非该串的长度大于等于 ,否则它都不是一个排列。
我们直接拿原数组中最大的数 。这样,只需要使得 三者之间的相对位置符合 在 和 中间即可。在这种情况下,只有 与原数组能组成排列,将排列数控制在了最小的 。
至于根据相对位置交换,可以暴力解决。若原来的数组就符合这个条件,随便找两个数跟自己交换就能保持这个样子不变。
源码
#include<bits/stdc++.h>
using namespace std;
using ui=unsigned int;
int main(void){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
size_t T;
cin>>T;
while (T--){
size_t n;
cin>>n;
vector<ui> a(n);
size_t onepos,twopos,npos;
for (size_t i=0;i<n;i++)
cin>>a[i],
a[i]==1?onepos=i+1 //记录1, 2, n的位置,用三目压行
:a[i]==2?twopos=i+1
:a[i]==n?npos=i+1
:0;
if (onepos < twopos && twopos < npos) cout<<twopos<<' '<<npos;
if (onepos < npos && npos < twopos) cout<<1<<' '<<1;
if (twopos < onepos && onepos < npos) cout<<onepos<<' '<<npos;
if (twopos < npos && npos < onepos) cout<<1<<' '<<1;
if (npos < onepos && onepos < twopos) cout<<onepos<<' '<<npos;
if (npos < twopos && twopos < onepos) cout<<twopos<<' '<<npos;
cout.put('\n');
}
return 0;
}