题目大意:
You are given an array of nn positive integers . You can perform the following operation any number of times: select several distinct indices i1,i2,…,iki1,i2,…,ik (1≤ij≤n1≤ij≤n) and move the number standing at the position i1i1 to the position i2i2, the number at the position i2i2 to the position i3i3, …, the number at the position ikik to the position i1i1. In other words, the operation cyclically shifts elements: i1→i2→…ik→i1i1→i2→…ik→i1.
For example, if you have n=4n=4, an array a1=10,a2=20,a3=30,a4=40a1=10,a2=20,a3=30,a4=40, and you choose three indices i1=2i1=2, i2=1i2=1, i3=4i3=4, then the resulting array would become a1=20,a2=40,a3=30,a4=10a1=20,a2=40,a3=30,a4=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 ss. 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 ss (, 0≤s≤2000000≤s≤200000)—the number of elements in the array and the upper bound on the sum of cycle lengths.
The next line contains nn integers —elements of the array (1≤ai≤1091≤ai≤109).
Output
If it’s impossible to sort the array using cycles of total length not exceeding ss, 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 2⋅q2⋅q lines print descriptions of operations in the order they are applied to the array. The description of ii-th operation begins with a single line containing one integer (1≤k≤n1≤k≤n)—the length of the cycle (that is, the number of selected indices). The next line should contain kk distinct integers (1≤ij≤n1≤ij≤n)—the indices of the cycle.
The sum of lengths of these cycles should be less than or equal to ss, and the array should be sorted after applying these operations.
If there are several possible answers with the optimal qq, 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;
}
本文介绍了一种通过有向图和并查集优化的数组排序算法,该算法在满足特定操作次数和位置限制的情况下,实现数组的非递减排序。算法核心在于通过直接移动元素到目标位置,形成环状结构,并在必要时合并环来减少操作次数。
380

被折叠的 条评论
为什么被折叠?



