[CF1525B]Permutation Sort
壹、题目描述 ¶
中文翻译:给你一个长度为 \(n\) 的排列,每次可以任意调动一个连续子区间的元素,求把这个区间变成一个升序排列的最小次数。注意,你不能一次性选择整个排列。
贰、题解 ¶
显然,“各居其所” 显然是最棒的 —— 因为我们不需要任何操作,这个排列本身就是有序的。
那么次一点的呢?那就是 \(1\) 在自己的位置上,或者 \(n\) 在自己的位置上,这个时候我们只需要选择子区间 \([2,n]\) 或者 \([1,n-1]\) 就可以使排序有序。如果同时成立,即 \(p_1=1\and p_n=1\),那么选择 \([2,n-1]\) 重排就好了。
再次一点的呢?那就是 \(1\) 和 \(n\) 都不在自己的位置上,即 \(p_1\neq 1\and p_n\neq n\),这个时候,我们只需要先进行一次操作,将 \(1\) 弄到一号位置(或者 \(n\) 弄到 \(n\) 号位置),就变成 “次一点” 的情况了。也就是说这种情况只需要两次咯?
不,不是的,如果只是那么简单,你会 \({\color{red}{\text{WA}}}\; \text{on test #2}\).
这说明这并没有那么简单,即我们前面的某个环节出问题了。哪里呢?注意到 “我们只需要先进行一次操作,将 \(1\) 弄到一号位置(或者 \(n\) 弄到 \(n\) 号位置)”,真的所有情况都只需要一步就可以到位?
考虑 \(p_1=n\and p_n=1\) 的情况,我们必须使用 \(2\) 次才能达到 “次一点” 的情形。
综上,我们有三种情况:
- 第一种,“各居其所”,不需要;
- 第二种,\(p_1=1\or p_n=1\),需要一次操作;
- 第三种,\(p_1=n\and p_n=1\),需要三次操作;
- 其他情况,两次操作;
判断一下就好了。
叁、参考代码 ¶
#define rep(i, l, r) for(int i=(l), i##_end_=(r); i<=i##_end_; ++i)
const int maxn=50;
int a[maxn+5], n;
signed main(){
rep(tmp, 1, readin(1)){
n=readin(1);
rep(i, 1, n) a[i]=readin(1);
int flg=1;
rep(i, 1, n) if(a[i]!=i){
flg=0; break;
}
if(flg){ printf("0\n"); continue; }
if(a[1]==n && a[n]==1) printf("3\n");
else if(a[1]!=1 && a[n]!=n) printf("2\n");
else printf("1\n");
}
return 0;
}