题解:P14972 『GTOI - 2C』Fliping
ridewindHE · · 题解
题目传送门
2026 年的第一篇题解。
题目大意
有一个长度为
思路
我们可以从头到尾依次判断是否正确,如果当前位不正确就要进行翻转,用一个队列存下答案。
这看似很容易解决,但是题目限制长度至少为
我们先用一个数组
#include<bits/stdc++.h>
using namespace std;
int n,a[2010],b[2010],aa[2010];
queue<pair<int,int> >q;
void swp(int l,int r){
q.push({l,r});
for(int i=l;i<=r;i++)aa[i]=a[i];
for(int i=l;i<=r;i++)a[i]=aa[r+l-i],b[a[i]]=i;
}
void A(int i){
int p=b[i];
swp(i,p);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[a[i]]=i;
}
for(int i=1;i<=n;i++){
if(a[i]==i)continue;
else A(i);
}
cout<<q.size()<<"\n";
while(q.size()){
auto k=q.front();
q.pop();
cout<<k.first<<" "<<k.second<<"\n";
}
return 0;
}
这可以得到 20 分。
我们接下来思考如果长度至少为
- 如果当前位满足
b_i-i+1\ge 3 ,我们可以直接用上面讲的操作,直接翻转[i,b_i] 。 - 如果当前位满足
n-b_i+1\ge 3 ,我们可以先翻转[b_i,n] ,再翻转[i,n] 。 - 如果以上两点都不满足,这看起来有些难度,我们来举个例子试试看:
1 2 3 4 5 6 8 7 9我们先翻转
[4,7] ,序列变为:1 2 3 8 6 5 4 7 9再翻转
[5,7] ,序列变为:1 2 3 8 4 5 6 7 9然后翻转
[5,8] ,序列变为:1 2 3 8 7 6 5 4 9最后翻转
[4,8] ,序列变为:1 2 3 4 5 6 7 8 9
我们只需要依次翻转
现在,我们已经处理好了所有情况,操作次数自然不超过
完整代码
#include<bits/stdc++.h>
using namespace std;
int n,a[2010],b[2010],aa[2010];
queue<pair<int,int> >q;
void swp(int l,int r){
q.push({l,r});
for(int i=l;i<=r;i++)aa[i]=a[i];
for(int i=l;i<=r;i++)a[i]=aa[r+l-i],b[a[i]]=i;
}
void A(int i){
int p=b[i];
swp(i,p);
}
void B(int i){
int p=b[i];
swp(p,n);
swp(i,n);
}
void C(int i){
if(i<=3){
cout<<-1;
exit(0);
}
int j=i-3,p=b[i];
swp(j,i);
swp(j+1,i);
swp(j+1,p);
swp(j,p);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[a[i]]=i;
}
for(int i=1;i<=n;i++){
if(a[i]==i)continue;
else if(b[i]-i+1>=3)A(i);
else if(n-b[i]+1>=3)B(i);
else C(i);
}
cout<<q.size()<<"\n";
while(q.size()){
auto k=q.front();
q.pop();
cout<<k.first<<" "<<k.second<<"\n";
}
return 0;
}