题解 | # 红魔馆的微瑕序位 #

红魔馆的微瑕序位

https://ac.nowcoder.com/acm/contest/127702/F

[排列的结论]

任意一个长度为的排列,如果可以交换任意两个元素,最终使其排列递增即的次数为
置换环是描述排列错位关系的核心结构,在的排列里,一群互相占据对方位置的数,顺着本该去的位置追踪,最终会形成一个闭环,这个闭环就是置换环
任意一个排列一定可以唯一的分解成若干个互不相交的置换环的并集,这是置换群伦中的一个基本定理
一个长度为的置换环中,环中的所有元素,没有一个在正确位置,且元素之间是循环错位的,那么操作一次可将一个长度为的置换环拆成一个长度为的置换环以及一个长度为的置换环.....由数学归纳法可得到操作次数是
假设长度为的排列中有个置换环,减去每个置换环少的一个次数,所以就是

这道题目求混乱度,那么就是存在一对相邻的位置交换,其他位置正确
  1. 如果存在满足在一个置换环里面,那么我可以减少一次操作不让在正确的位置上,使得满足混乱度等于
  2. 如果所有的都不满足在一个置换环里面,那么只能将排列先进行次操作变成,然后额外操作一次让混乱度等于
这段代码求出置换环的数量,并对每一个经行编号
vector<int> pid(n + 1);
vector<bool> vis(n + 1);
int idx = 0;
for(int i = 1; i <= n; i ++){
    if(vis[a[i]]) continue;
    int x = a[i];
    idx ++;
    while(!vis[x]){
        vis[x] = true;
        pid[x] = idx;
        x = a[x]; 
    }   
}

总代码:
#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;

void solve(){
    int n; cin >> n;
    vector<int> a(n + 1), pid(n + 1);
    vector<bool> vis(n + 1);
    for(int i = 1; i <= n; i ++) cin >> a[i];
    int idx = 0;
    for(int i = 1; i <= n; i ++){
        if(vis[a[i]]) continue;
        idx ++;
        int x = a[i];
        while(!vis[x]){
            vis[x] = true;
            pid[x] = idx;
            x = a[x];
        }
    }
    int flag = 1;
    for(int i = 1; i <= n - 1; i ++){
        if(pid[i] == pid[i + 1]){
            flag = -1;
            break;
        }
    }
    cout << n - idx + flag << endl;
    return ;
}
signed main(){
    HelloWorld;
    
    int tt; cin >> tt;
    while(tt --) solve();
    return 0;
}
全部评论

相关推荐

哞客37422655...:这就是真实社会,没有花里胡哨的安慰,让你感受到阶级分明,不浪费彼此时间。虽然露骨但是唉
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务