正题
这题的构造方式的确巧妙.
先讲做法,个人觉得如果不是做过类似的题不太能想出来.
将b翻转,看看与a交的部分,如果没有交,直接输出,否则交的部分肯定是一个区间,找到值为这个交区间元素值的并区间,用不在并区间的元素和交区间里面的元素一一交换即可,如果换不上了,那么就无解.
如果交的区间长度为k,设a序列中该值元素个数为A个,b序列中该值元素个数为B个,那么就有并区间长度为A+B-k,现在要证明如果两边的元素<交的长度,那么无解,也就是有n-(A+B-k)<k,即n<A+B,b中的该值元素无论怎么放都必定会碰上a中的该值元素.
总结
Atcoder思维题好难啊,知道解法也感觉不太能想出来,能想到的唯一思维方式就是先考虑什么情况肯定无解,在两个序列出现总次数最多的>n,再考虑如何对<=的情况构造出解,下一步就要想到将b翻转,令交最多是一个区间,这一步就很离谱,再思考交的区间与外面换是否符合正确性.得到的经验大概就是"翻转"这个操作吧?
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int a[N],b[N],n;
int main(){
scanf("%d",&n);
int x;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
reverse(b+1,b+1+n);
int l=0,r=0,t=0,L=0,R=0;
for(int i=1;i<=n;i++) if(a[i]==b[i]) {
if(!l) l=i,r=i,t=a[i];
else r++;
}
if(!l){
printf("Yes\n");
for(int i=1;i<=n;i++) printf("%d ",b[i]);
return 0;
}
for(int i=1;i<=n;i++) if(a[i]==t || b[i]==t) {L=i-1;break;}
for(int i=n;i>=1;i--) if(a[i]==t || b[i]==t) {R=i+1;break;}
if(L+n-R+1<(r-l+1)) printf("No\n");
else{
for(int i=1;i<=min(L,r-l+1);i++) swap(b[i],b[l+i-1]);
for(int i=1;i<=r-l+1-min(r-l+1,L);i++) swap(b[n-i+1],b[r-i+1]);
printf("Yes\n");
for(int i=1;i<=n;i++) printf("%d ",b[i]);
}
}

本文深入解析AtCoder平台上的一个思维挑战题,通过序列翻转和元素交换策略解决序列匹配问题。文章详细阐述了解题思路,从无解条件到构造解的步骤,并附带代码实现,为读者提供了一个全面的理解视角。
3006

被折叠的 条评论
为什么被折叠?



