The 9th CCPC (Harbin) Onsite(The 2nd Universal Cup. Stage 10: Harbin)
L. Palm Island
题意:
Toph 正在玩纸牌游戏。她有 n n n 张牌,每张牌都有一个唯一的数字 1 , 2 ⋯ n 1,2\cdots n 1,2⋯n 。在这个游戏中,Toph 可以操作这副扑克牌。我们不妨假设从牌顶到牌底的牌都是 p 1 , p 2 , ⋯ p n p_1,p_2,\cdots p_n p1,p2,⋯pn (一种排列),那么每次操作都必须是以下两种情况之一:
- 将最上面的牌放在牌的最下面,也就是将牌的顺序变为 p 2 , p 3 ⋯ p n , p 1 p_2,p_3\cdots p_n,p_1 p2,p3⋯pn,p1 。
- 将最上面的第二张牌放在牌底,即改变牌序为 p 1 , p 3 ⋯ p n , p 2 p_1,p_3\cdots p_n,p_2 p1,p3⋯pn,p2 。
现在,你知道 Toph 的牌的初始顺序(从上到下)是 a 1 , a 2 , ⋯ a n a_1,a_2,\cdots a_n a1,a2,⋯an ,Toph 想在进行一些操作后将牌的顺序变为 b 1 , b 2 , ⋯ b n b_1,b_2,\cdots b_n b1,b2,⋯bn 。请构建操作序列以帮助 Toph 实现更改。
Toph 没有耐心。因此操作次数不应超过 n 2 n^2 n2 。
思路:
a 1 , a 2 , ⋯ a n a_1,a_2,\cdots a_n a1,a2,⋯an 到 b 1 , b 2 , ⋯ b n b_1,b_2,\cdots b_n b1,b2,⋯bn。从一个排列到另一个排列,说明每个数都不重复,每个数要呆的位置一定是确定的,我们把一个混乱的排列a变成最终的b,相当于排序了。
具体来说,我们按最终的排列b的顺序重新为排列中的数规定大小,然后a中对应的数也随之变化成新的数,那么相当于对排列a进行排序。现在问题就变成了如何使用上述操作在 n 2 n^2 n2 次操作内将数排序,并且还要打印操作序列。
- 如果我们进行若干次操作1,再进行若干次操作2,直到进行n-1次把
p
n
p_n
pn 也操作到最后面,这时前面会剩下一个数
p
i
p_i
pi,这时再进行操作1,
p
i
p_i
pi 就排到了数列的末尾,同时其他数相对位置不变。同理,第二轮进行n-2次,再进行两次操作1,就把
p
j
p_j
pj 和
p
i
p_i
pi 也放到末尾。类推。
这样就实现了一个类似选择排序的操作,而选择排序最多只需要跑n趟,每趟n次操作,总的不会超过 n 2 n^2 n2 次。 - 发现先进行一次操作2移动
p
i
+
1
p_{i+1}
pi+1,再进行一次操作1移动
p
i
p_{i}
pi 的话,相当于把它两个交换了位置。同理,先进行两次操作2移动
p
i
+
1
,
p
i
+
2
p_{i+1},p_{i+2}
pi+1,pi+2,再进行一次操作1移动
p
i
p_{i}
pi 的话,相当于把
p
i
p_{i}
pi 放到了
p
i
+
1
,
p
i
+
2
p_{i+1},p_{i+2}
pi+1,pi+2 之后,相当于先和
p
i
+
1
p_{i+1}
pi+1 交换位置,再和
p
i
+
2
p_{i+2}
pi+2 交换位置。
换句话说,只要当前的数和它后面的数需要在新序列中交换位置,就使用一次操作2,否则就使用操作1。这样就可以实现一个类似冒泡排序的做法,同理总的操作次数不会超过 n 2 n^2 n2 次
code:
类选择排序:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1005;
int T,n;
int a[maxn],t[maxn];
pair<int,int> b[maxn];
int main(){
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++)
cin>>t[i];
for(int i=1;i<=n;i++){
b[i].second=i;
cin>>b[i].first;
}
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
a[i]=b[t[i]].second;
for(int round=1;round<n;round++){
int f=0;
for(int i=1;i<=n-round;i++){
if(a[i]==n-round+1)f=i;
printf("%d",(f!=0)+1);
}
for(int i=1;i<=round;i++)
printf("1");
if(f!=0)
for(int i=f;i<=n-round;i++)
swap(a[i],a[i+1]);
}
puts("");
}
return 0;
}
类冒泡排序
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1005;
int T,n;
int a[maxn],t[maxn];
pair<int,int> b[maxn];
int main(){
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++)
cin>>t[i];
for(int i=1;i<=n;i++){
b[i].second=i;
cin>>b[i].first;
}
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
a[i]=b[t[i]].second;
for(int round=1;round<n;round++){
for(int i=1;i<n;i++)
if(a[i]>a[i+1]){
swap(a[i],a[i+1]);
printf("2");
}
else printf("1");
printf("1");
}
puts("");
}
return 0;
}