题解 P6305 【[eJOI2018]循环排序】
解析
首先考虑
考虑将
一个想法是对每个环做一次操作,操作中选择的下标数量的和就是所有操作环的大小的和
但如果
这样排列的情况就做完了
接着考虑
设想将所有值相同的
于是我们的思路就清晰了。至于求出欧拉回路后的做法和排列的情况就差不多了(得到的欧拉回路序列可以直接看做遍历一个环得到的序列)
CODE
一个实现的 trick 是将序列下标作为边 id 标记在边上,这样得到的欧拉回路直接就是一个合法的操作序列;这个具体可见代码
另外由于对于 “合并多个环” 这个操作还需要输出具体的操作序列,其细节的对应关系可能比较火葬场;我的代码有点对着数据调试的感觉qaq,不要深究(可能有时间会回来对这部分补一些注释...)
#include <cstdio>
#include <algorithm>
#include <vector>
using std::sort;
using std::unique;
using std::lower_bound;
using std::vector;
using std::pair;
using std::min;
typedef pair<int, int> pad;
const int MAXN =2e5+20;
/*------------------------------IO------------------------------*/
int read(){
int x =0; char c =getchar();
while(c < '0' || c > '9') c =getchar();
while(c >= '0' && c <= '9') x =(x<<1)+(x<<3)+(48^c), c =getchar();
return x;
}
void write(const int &x){
if(x/10)
write(x/10);
putchar('0'+x%10);
}
/*------------------------------Map------------------------------*/
vector<pad> E[MAXN];
inline void addedge(const int &u, const int &v, const int &w){
E[u].push_back(pad(v, w));
}
/*------------------------------Dfs------------------------------*/
vector<int> ans[MAXN];
int tot;
bool vis[MAXN];
void dfs(const int &u){
vis[u] =1;
while(!E[u].empty()){
int v =E[u].back().first, w =E[u].back().second;
E[u].pop_back();
dfs(v);
ans[tot].push_back(w);
}
}
/*------------------------------Main------------------------------*/
int a[MAXN];
int main(){
int n =read(), s =read();
int tmp[MAXN];
for(int i =0; i < n; ++i)
tmp[i] =a[i] =read();
sort(tmp, tmp+n);
int b[MAXN], col =1;
for(int i =0; i < n; ++i){
b[i] =col;
if(i != n-1 && tmp[i+1] != tmp[i])
++col;
}
unique(tmp, tmp+n);
for(int i =0; i < n; ++i)
a[i] =lower_bound(tmp, tmp+col, a[i])-tmp+1;
for(int i =0; i < n; ++i)
if(a[i] != b[i])
addedge(a[i], b[i], i+1);
// init done. //
int sum =0;
for(int i =1; i <= col; ++i)
if(!vis[i]){
dfs(i);
if(ans[tot].size() != 0){
sum +=ans[tot].size();
++tot;
}
}
if(sum > s)
putchar('-'), putchar('1'), putchar('\n');
else if(s-sum <= 1 || tot <= 1){
write(tot), putchar('\n');
for(int i =0; i < tot; ++i){
write(ans[i].size()), putchar('\n');
for(int j =0; j < (int)ans[i].size(); ++j)
write(ans[i][j]), putchar(' ');
putchar('\n');
}
}
else{
int ans_tot =tot-min(s-sum, tot)+2;
write(ans_tot), putchar('\n');
for(int i =0; i < ans_tot-2; ++i){
write(ans[i].size()), putchar('\n');
for(int j =0; j < (int)ans[i].size(); ++j)
write(ans[i][j]), putchar(' ');
putchar('\n');
}
vector<int> tmp[2];
int lst =-1;
for(int i =tot-1; i >= ans_tot-2; --i){
tmp[0].push_back(ans[i][ans[i].size()-1-1]);
ans[i].back() ^=lst ^=ans[i].back() ^=lst;
}
ans[tot-1].back() =lst;
for(int i =ans_tot-2; i < tot; ++i)
for(int j =0; j < (int)ans[i].size(); ++j)
tmp[1].push_back(ans[i][j]);
for(int i =0; i < 2; ++i){
write(tmp[i].size()), putchar('\n');
for(int j =0; j < (int)tmp[i].size(); ++j)
write(tmp[i][j]), putchar(' ');
putchar('\n');
}
}
}