CF1012E Cycle sort 题解

题目链接

点击打开链接

题目解法

\(b\)\(a\) 排序之后的序列
首先无解就是 \(a_i\neq b_i\) 的位置 \(>k\)

这种问题的简化版是排列
我们先考虑排列的情况
轮换问题可以想到建出置换环(\(i\to a_i\)
我们有两种方式构造轮换序列:

  1. 对于每个非自环,按顺序输出
    操作数为:非自环的环数,\(\sum k\) 为:非自环的点数
  2. 整体按照顺序输出每个环,发现这样操作之后会形成一个置换环,再对这个环操作一次
    举个例子(置换环自己画出):
    \(a: 2,3,4,1,6,7,5,9,8\)
    整体操作一次之后的序列:\(8,2,3,4,1,6,7,5,9\)
    这个序列形成的置换环是 \(1,8,5\),操作一次即可
    操作数为:\(2\)\(\sum k\) 为:非自环的点数 + 环数

因为 \(k\) 有限制,所以我们尽量多的采用构造 \(2\),其余的用构造 \(1\) 输出

再考虑原问题
我们先随便连出一堆置换环,观察到有 \(a\) 相同的点的置换环可以合并
尽可能多合并即可
最后按照上面排列的方式做就好了

时间复杂度 \(O(n\log n)\)

#include <bits/stdc++.h>
#define F(i,x,y) for(int i=(x);i<=(y);i++)
#define DF(i,x,y) for(int i=(x);i>=(y);i--)
#define ms(x,y) memset(x,y,sizeof(x))
#define SZ(x) (int)x.size()-1
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int,int> pii;
template<typename T> void chkmax(T &x,T y){ x=max(x,y);}
template<typename T> void chkmin(T &x,T y){ x=min(x,y);}
template<typename T> void read(T &FF){
    FF=0;int RR=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
    for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
    FF*=RR;
}
const int N=200010;
int n,k,a[N],b[N],c[N];
vector<int> v1[N],v2[N];
map<int,int> mp;
int fa[N];bool vis[N];
int gfa(int x){ return x==fa[x]?x:fa[x]=gfa(fa[x]);}
void merge(int x,int y){ fa[gfa(x)]=gfa(y);}
bool prt[N];
vector<int> ans;
void dfs(int u){
    prt[u]=1,ans.pb(u);
    if(!prt[c[u]]) dfs(c[u]);
}
int ver[N];
int main(){
    read(n),read(k);
    F(i,1,n) read(a[i]),b[i]=a[i];
    sort(b+1,b+n+1);
    int cnt=0;
    F(i,1,n) if(b[i]!=b[i-1]) mp[b[i]]=++cnt;
    F(i,1,n) a[i]=mp[a[i]],b[i]=mp[b[i]];
    int res=0;
    F(i,1,n) if(a[i]!=b[i]){
        res++;
        v1[b[i]].pb(i),v2[a[i]].pb(i);
    }
    if(res>k){ puts("-1");exit(0);}
    F(i,1,n) fa[i]=i;
    F(i,1,n) if(a[i]!=b[i]) c[i]=v1[a[i]].back(),v1[a[i]].pop_back();
    F(i,1,n) merge(i,c[i]);
    F(i,1,cnt)
        F(j,1,SZ(v2[i])){
            int a=v2[i][j-1],b=v2[i][j];
            int x=gfa(a),y=gfa(b);
            if(x!=y) swap(c[a],c[b]),fa[x]=y;
        }
    F(i,1,n) if(a[i]!=b[i]) ver[gfa(i)]=i;
    int cir=0;
    F(i,1,n) if(ver[i]) cir++;
    int jt=min(k-res,cir);
    if(jt<=2) printf("%d\n",cir),jt=0;
    else printf("%d\n",2+cir-jt);
    int i=1;
    if(jt){
        int rs=0;
        vector<int> ans1,ans2;
        for(;i<=n;i++) if(ver[i]){
            rs++;
            if(rs>jt) break;
            int cur=ver[i];
            while(true){
                ans1.pb(cur),cur=c[cur];
                if(cur==ver[i]) break;
            }
            ans2.pb(ver[i]);
        }
        reverse(ans2.begin(),ans2.end());
        printf("%d\n",(int)ans1.size());
        for(int x:ans1) printf("%d ",x);puts("");
        printf("%d\n",(int)ans2.size());
        for(int x:ans2) printf("%d ",x);puts("");
    }
    for(;i<=n;i++) if(ver[i]){
        vector<int> ans;
        int cur=ver[i];
        while(true){
            ans.pb(cur),cur=c[cur];
            if(cur==ver[i]) break;
        }
        printf("%d\n",(int)ans.size());
        for(int x:ans) printf("%d ",x);puts("");
    }
    return 0;
}

posted @ 2024-06-27 22:23  Farmer_D  阅读(16)  评论(0)    收藏  举报