题解 P6447 [COCI2010-2011#1] ŽABE
洛谷。
题意
一共有
每次操作,可以使编号为
(比较想知道为什么我们的翻译是青蛙)。
分析
这是一道构造题,我们需要使两个序列相近。
令原序列为
对于这个
我们在使序列接近我们的
每次,我们使两个
不妨令
- 使
i 移动到i+1 的左侧。 - 使
i 到i+1 中间的数都移动开。
对于第一种,我们可以在模拟的过程中发现,我们移动
也就是说,我们移动
这也就使得,我们这种移动方式可能不能仅靠移动
对于第二种,我们贪心上可以从小到大移动这些数,是这些数移出这个区间内。
这时我们发现,我们的
稍微证明一下,假如我们的另一个区间的之间长度为
然后我们就可以使我们的区间不断移动出这个区间了。
于是,我们就可以解决了从
而我们从
inline int find(int a[],int x) {
for(int i=1; i<=n; ++i) if(a[i]==x) return i;
}
inline bool check(int L,int R,int x) {
if(L<R) return L<x&&x<R;
else return x<R||L<x;
}
inline void solve(int a[],int to[],bool flag) {
top=0;
for(int i=n-1; i; --i) {
while(1) {
int L=find(a,i);
int R=find(a,i+1);
if(L%n+1==R) break;
int idx=L%n+1;
for(int j=L%n+1; j!=R; j=j%n+1) if(a[j]<a[idx]) idx=j;
R=find(a,n);
while(check(L,R,idx)) {
ans[++top]=a[idx];
int cnt=a[idx];
while(cnt--) {
swap(a[idx],a[to[idx]]);
if(a[idx]==n) R=idx;
else if(a[idx]==i) L=idx;
idx=to[idx];
}
}
}
}
if(!flag) for(int i=1; i<=top; ++i) cout<<ans[i]<<"\n";
else for(int i=top; i; --i) cout<<ans[i]<<"\n";
}