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;
}
本文作者:Creeper_l
本文链接:https://www.cnblogs.com/Creeperl/p/18202484
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
题解
【推荐】100%开源!大型工业跨平台软件C++源码提供,建模,组态!
【推荐】2025 HarmonyOS 鸿蒙创新赛正式启动,百万大奖等你挑战
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】开源 Linux 服务器运维管理面板 1Panel V2 版本正式发布
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步