[loj2818][eJOI2018]循环排序——思维题 大佬们的博客 Some Links

版权声明:欢迎大家转载,转载请标明出处。 https://blog.csdn.net/ylsoi/article/details/82019850

题目大意:

You are given an array of n positive integers a 1 , a 2 , , a n . You can perform the following operation any number of times: select several distinct indices i 1 , i 2 , , i k ( 1 i j n ) and move the number standing at the position i 1 to the position i 2 , the number at the position i 2 to the position i 3 , …, the number at the position i k to the position i 1 . In other words, the operation cyclically shifts elements: i 1 i 2 i k i 1 .
For example, if you have n = 4 , an array a 1 = 10 , a 2 = 20 , a 3 = 30 , a 4 = 40 , and you choose three indices i 1 = 2 , i 2 = 1 , i 3 = 4 , then the resulting array would become a 1 = 20 , a 2 = 40 , a 3 = 30 , a 4 = 10 .
Your goal is to make the array sorted in non-decreasing order with the minimum number of operations. The additional constraint is that the sum of cycle lengths over all operations should be less than or equal to a number s . If it’s impossible to sort the array while satisfying that constraint, your solution should report that as well.
Input
The first line of the input contains two integers n and s ( 1 n 200 000 , 0 s 200 000 )—the number of elements in the array and the upper bound on the sum of cycle lengths.
The next line contains n integers a 1 , a 2 , , a n —elements of the array ( 1 a i 10 9 ).
Output
If it’s impossible to sort the array using cycles of total length not exceeding s , print a single number “-1” (quotes for clarity).
Otherwise, print a single number q — the minimum number of operations required to sort the array.
On the next 2 q lines print descriptions of operations in the order they are applied to the array. The description of i -th operation begins with a single line containing one integer k ( 1 k n )—the length of the cycle (that is, the number of selected indices). The next line should contain k distinct integers i 1 , i 2 , , i k ( 1 i j n )—the indices of the cycle.
The sum of lengths of these cycles should be less than or equal to s , and the array should be sorted after applying these q operations.
If there are several possible answers with the optimal q , print any of them.

思路:

考虑一个位置的数,如果它要去另外一个位置的话,直接移动到另外一个位置一定是最优的,因为如果移动到其它的地方之后又要移动回来。
所以最后就是一个有若干个环的有向图。操作次数最少的方法是所有的数全部移动一次,之后每个环内错位的数再移动一次。操作位置最少的方法是每个环单独移动。
这里求的是操作的次数最少,不难发现操作次数最少就有可能满足不了操作位置的限制,所以我们可以单独移动一些环,使得操作位置符合要求的情况下操作次数最少。
如果有相同的数的话他们是可以任意连边的,但是这样会增加环的个数,不难发现如果两个环内有相同的数字的话是可以合并成一个环的,用并查集维护。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define pii pair<int,int>
#define fi first
#define se second
#define mk make_pair
typedef long long ll;

using namespace std;

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

void File(){
    freopen("gen.in","r",stdin);
    freopen("gen.out","w",stdout);
}

const int maxn=2e5+10;
int n,m,a[maxn],to[maxn],ans,cnt,tot,num[maxn];
pii b[maxn];
bool yes[maxn],vis[maxn];

int fa[maxn];
int find(int x){return fa[x]==x ? x : fa[x]=find(fa[x]);}

void init(){
    read(n); read(m);
    REP(i,1,n)read(a[i]),b[i]=mk(a[i],i);
    sort(b+1,b+n+1);
    REP(i,1,n)if(a[i]==b[i].fi)yes[i]=1;
    REP(i,1,n)fa[i]=i;
    int p=1;
    REP(i,1,n){
        if(yes[b[i].se])continue;
        while(yes[p])++p;
        to[b[i].se]=p++;
        fa[find(b[i].se)]=find(to[b[i].se]);
    }
    REP(i,1,n){
        int l=i,r=i,las=0;
        while(b[r+1].fi==b[l].fi)++r;
        REP(j,l,r){
            if(yes[b[j].se])continue;
            if(!las){las=j;continue;}
            if(find(b[las].se)==find(b[j].se))continue;
            fa[find(b[las].se)]=find(b[j].se);
            swap(to[b[las].se],to[b[j].se]);
            las=j;
        }
        i=r;
    }
}

int Mincost(){return tot<=2 ? cnt : tot+cnt;}

int solve(int x){
    int qu[maxn],q=0,p=to[x];
    qu[++q]=x;
    while(p!=x)qu[++q]=p,p=to[p];
    printf("%d\n",q);
    REP(i,1,q)printf("%d ",qu[i]);
    putchar('\n');
    return q;
}

void work(){
    REP(i,1,n){
        if(yes[i])continue;
        ++cnt;
        if(!vis[find(i)]){
            num[++tot]=find(i);
            vis[find(i)]=1;
        }
    }
    if(cnt>m){puts("-1");return;}
    if((tot>2 ? cnt+tot : cnt)<=m)ans=2;
    else ans=2+cnt+tot-m;
    ans=min(ans,tot);
    printf("%d\n",ans);
    while((tot>1 ? cnt+tot : cnt)>m){
        int cost=solve(num[tot]);
        m-=cost; cnt-=cost; --tot;
    }
    if(tot==1)solve(num[tot]);
    else if(tot){
        int qu[maxn],q1[maxn],q=0,qq=0;
        while(tot){
            int p=to[num[tot]]; qu[++q]=num[tot]; q1[++qq]=num[tot];
            while(p!=num[tot])qu[++q]=p,p=to[p];
            --tot;
        }
        printf("%d\n",q);
        REP(i,1,q)printf("%d ",qu[i]);
        putchar('\n');
        printf("%d\n",qq);
        DREP(i,qq,1)printf("%d ",q1[i]);
        putchar('\n');
    }
} 
int main(){
    File();
    init();
    work();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/82019850