伞兵题,写了一下午。
开始想错了构造方法,写完才发现,然后又想和写了很久(
给出一个排列,每次可以把其划分成若干段,段内不变,段出现顺序反转,求构造方案使排列有序。
题目要求在 \(n\) 次内完成排序,这引导着我们想到一次排上一个,要是能够第一次把 \(1\) 放在最前面,第二次把 \(2\) 放在第二个直到第 \(n\) 次把 \(n\) 放在最后一个就好了。
但试了试发现这没法做到,那就退而求其次,不要求顺序,只要把这几个数放在一起就可以了,即第一次其中有一块是 \(1\),第二次有一块是 \(12\) 或 \(21\),第三次有一块是 \(123\) 或 \(321\),以此类推。
我一开始的想法是倒着来,因为要翻转嘛,那么从后往前排,但这样和直接从前往后没有什么区别。
既然是翻转,那么就想个办法把连续的数放前面或反转后放后面,这样是可以做到的。举个例子,\(3/15624 \to 1/562/43 \to 4/356/2/1 \to 1/2/3/564 \to 564321 \to \cdots\)
容易发现,只要枚举当前新放进去的数,把小于它的数前面或后面划开,并把这个数前面或后面划开就可以了。
在实现上,我写了个结构体,维护了一个能自由切割和拼接的数组,使代码更清晰。
如果在 CF 赛场上遇到这题恐怕要写很久,因为开始想了个错误的 构造写了半天,代码细节也有些多。
#include <iostream>
#include <algorithm>
#include <vector>
struct twt {
std::vector<int> a;
twt() { a.clear(); }
void push(int x) { a.push_back(x); }
int find(int x) {
int an = a.size() + 1;
for (int i = 0; i < (int)a.size(); i++)
if (a[i] == x) return i+1;
return an;
}
twt sub(int l, int r) {
twt an;
for (int i = l; i <= r; i++) {
if (i < 1 || i > (int)a.size()) return twt();
an.push(a[i-1]);
}
return an;
}
twt operator + (twt y) {
twt an = *this;
an.a.insert(an.a.end(), y.a.begin(), y.a.end());
return an;
}
bool fin() {
for (int i = 0; i < (int)a.size(); i++)
if (a[i] != i+1) return false;
return true;
}
int size() { return a.size(); }
} now;
int n, x, ttt;
std::vector<int> pr, tmp;
std::vector<twt> dwd;
std::vector<std::vector<int> > ans;
std::ostream& operator << (std::ostream& out, twt x) {
for (int i = 0; i < (int)x.a.size(); i++) out << x.a[i] << ' ';
out << "#\n";
return out;
}
int main() {
std::cin >> n;
for (int i = 1; i <= n; i++) std::cin >> x, now.push(x);
if (now.a[0] != 1) {
pr.clear(); pr.push_back(now.find(1)-1), pr.push_back(n-now.find(1)+1), ans.push_back(pr);
now = now.sub(now.find(1), n) + now.sub(1, now.find(1)-1);
}
for (int i = 2; !now.fin() && i <= n; i++) {
pr.clear(), tmp.clear(), dwd.clear();
for (int j = 1; j < i; j++) tmp.push_back(now.find(j));
tmp.push_back(now.find(i));
if (now.a[0] == 1) tmp.push_back(0); else tmp.push_back(1);
if (now.a[0] == 1) tmp.push_back(n); else tmp.push_back(n+1);
std::sort(tmp.begin(), tmp.end());
for (int j = 1; j < (int)tmp.size(); j++)
if (tmp[j] != tmp[j-1]) pr.push_back(tmp[j] - tmp[j-1]);
ans.push_back(pr);
for (int i = 0, l = 1; i < (int)pr.size(); l += pr[i], i++)
dwd.push_back(now.sub(l, l+pr[i]-1));
now = twt();
for (int i = (int)dwd.size()-1; i >= 0; i--)
now = now + dwd[i];
}
std::cout << ans.size() << '\n';
for (int i = 0; i < (int)ans.size(); i++, std::cout << '\n') {
std::cout << ans[i].size() << ' ';
for (int j = 0; j < (int)ans[i].size(); j++)
std::cout << ans[i][j] << ' ';
}
}