CF1973E Cat, Fox and Swaps 题解

题意:对于一个长度为 \(n\) 的排列,求有多少对 \((l,r)\) 满足 \(1 \le l,r \le 2n\),且可以通过交换任意次 \(x,y(l \le x+y \le r)\) 使得原排列升序。

首先我们可以找到 \(i \ne a_i\) 的最小和最大的 \(i\),假设为 \(L\)\(R\)。若不存在则说明已经升序。

会发现满足条件的必要条件是:\(l \le L + n,r \ge R + 1\)

神奇的是若除开 \(l=r\) 的情况,上述条件也是充分条件,证明如下:

对于一个数 \(L \le x \le R-1\),我们先找到一个 \(y\) 满足 \(l \le y < r\)\(1 \le y-x \le n\),这个 \(y\) 一定存在的。那么我们可以通过交换 \((x,y-x),(y-x,x+1),(x,y-x)\) 达到交换 \((x,x+1)\) 的目的。即对于任意的 \(L \le x \le R\),我们都能做到交换 \((x,x+1)\)(并且其它数的位置不变),显然这一定能使原序列排序。

注意当 \(l=r\) 的情况时上述条件不一定成立,需要特殊考虑一下。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 1e5 + 10;
int n,T,a[MAXN];
signed main() {
	for(cin >> T;T;T--) {
		cin >> n;
		int l = -1,r = -1,ans = 0,flag = 0;
		for(int i = 1;i <= n;i++) cin >> a[i];
		for(int i = 1;i <= n;i++) 
			if(a[i] != i) {
				if(flag == -1) break;
				if(flag == 0) flag = a[i] + i;
				else if(flag != a[i] + i) flag = -1;
			} 
		for(int i = 1;i <= n;i++) if(a[i] != i) r = i;
		for(int i = n;i >= 1;i--) if(a[i] != i) l = i;
		if(l == -1) l = 2 * n,r = 1;
		else l = l + n,r = r + 1;
		for(int i = r;i <= 2 * n;i++)
			ans += min(i - 1,l);
		if(flag == 0) ans += 2 * n;
		if(flag > 0) ans += 1;
		cout << ans << endl; 
	}
	return 0;
}
posted @ 2024-05-20 17:35  Creeper_l  阅读(40)  评论(0编辑  收藏  举报