题目大意
三根柱子,
n
n
n 个盘子,编号
1
1
1~
n
n
n,开始时盘子乱序套在一根柱子上。
构造一种方案,用
1
0
6
10^6
106 以内步数使所有盘子以递增序套在一根柱子上。
n
≤
1
0
4
n \leq 10^4
n≤104
题解
这个题的目的是要把盘子排序。
1
0
4
10^4
104 和
1
0
6
10^6
106 是什么关系呢?——
n
log
n
n \log n
nlogn?
n
log
n
n \log n
nlogn 有什么排序算法呢?——快排?归并?
要用一个不太依赖比较的排序,于是选择归并。
设当前柱子我们对
[
l
,
r
]
[l,r]
[l,r] 进行排序,那么可以把盘子平均分到另两根柱子上,把他们分别排好序,再线性合并。
这样就是
O
(
n
log
n
)
O(n \log n)
O(nlogn) 的了。
代码
#include<cstdio>
#include<vector>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int maxn=1e4+5, maxk=1e6+5;
struct op{
int a,b;
};
int n,ans0;
vector<int> a;
op ans[maxk];
int d0,d[maxn];
void dq(int a,int b,int c,vector<int> &v) {
if (v.size()==1) return;
int sz=v.size(), mid=sz>>1, sz1=mid, sz2=sz-mid;
vector<int> v1,v2; v1.clear(); v2.clear();
fd(i,mid,1) {
ans[++ans0]=(op){a,b};
v1.push_back(-v[i-1]);
}
fd(i,sz,mid+1) {
ans[++ans0]=(op){a,c};
v2.push_back(-v[i-1]);
}
dq(b,a,c,v1);
dq(c,a,b,v2);
d0=0;
for(int i=0, j=0; i<sz1 || j<sz2; ) if (i<sz1 && (j>=sz2 || -v1[i]>-v2[j])) {
d[++d0]=-v1[i++];
ans[++ans0]=(op){b,a};
} else {
d[++d0]=-v2[j++];
ans[++ans0]=(op){c,a};
}
v.clear();
fd(i,d0,1) v.push_back(d[i]);
}
int main() {
scanf("%d",&n);
fo(i,1,n) {
int x;
scanf("%d",&x);
a.push_back(x);
}
dq(1,2,3,a);
printf("%d\n",ans0);
fo(i,1,ans0) printf("%d %d\n",ans[i].a,ans[i].b);
}