题目大意:
You are given an array of
positive integers
. You can perform the following operation any number of times: select several distinct indices
(
) and move the number standing at the position
to the position
, the number at the position
to the position
, …, the number at the position
to the position
. In other words, the operation cyclically shifts elements:
.
For example, if you have
, an array
, and you choose three indices
,
,
, then the resulting array would become
.
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
. 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
and
(
,
)—the number of elements in the array and the upper bound on the sum of cycle lengths.
The next line contains
integers
—elements of the array (
).
Output
If it’s impossible to sort the array using cycles of total length not exceeding
, print a single number “-1” (quotes for clarity).
Otherwise, print a single number
— the minimum number of operations required to sort the array.
On the next
lines print descriptions of operations in the order they are applied to the array. The description of
-th operation begins with a single line containing one integer
(
)—the length of the cycle (that is, the number of selected indices). The next line should contain
distinct integers
(
)—the indices of the cycle.
The sum of lengths of these cycles should be less than or equal to
, and the array should be sorted after applying these
operations.
If there are several possible answers with the optimal
, 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;
}