题目:
排列指的是值域连续的(从1到n),但并不一定是单调递增的序列。
这道题明显可以根据不同情况分类讨论,但情况太冗杂,考虑问题的本质,从而降低讨论难度。
本质:一个排列被写错了一个,那么1到n中的每一个数一定有一个数出现了两次,还有一个数出现了0次。而正确的序列就是由出现两次的数改成没有出现的数即可。然后这两种改变后,与另一个人比较一下,如果另一个人与改变后的序列相比较,只差1个就成立。由于有两种改变,每一种检查一下,然后输出成立的并且字典序最小的即可。
如何处理这类分类讨论的(水题):分析问题,画思维导图,出多种数据检查是否考虑完所有情况,以及代码是否实现正确。
#include<bits/stdc++.h> using namespace std; #define N 100005 int n,a[N],b[N],cnt=0,cnta=0,shu,vis[N],c[N],d=0; int main() { freopen("seq.in","r",stdin); freopen("seq.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),vis[a[i]]++; for(int i=1;i<=n;i++){ scanf("%d",&b[i]); if(a[i]!=b[i]) cnt++; } if(cnt>=3) { printf("Impossible "); return 0; } for(int i=1;i<=n;i++) if(!vis[i]) cnta++,shu=i; if(cnta>1||cnta==0) { printf("Impossible "); return 0; } int fl=0,rt=0; for(int i=1;i<=n;i++) if(vis[a[i]]==2){ int xx=a[i],cntb=0; a[i]=shu; for(int j=1;j<=n;j++) if(b[j]!=a[j]) cntb++; if(cntb==1&&rt==0){ for(int j=1;j<=n;j++) c[j]=a[j]; rt++; } else if(cntb==1) { rt++; break; } a[i]=xx; } if(!rt) { printf("Impossible "); return 0; } if(rt==1){ for(int i=1;i<=n;i++) printf("%d ",c[i]); return 0; } for(int j=1;j<=n;j++) if(c[j]>a[j]) { d=1; break; } else if(c[j]<a[j]) { d=0; break; } if(d){ for(int j=1;j<=n;j++) printf("%d ",a[j]); } else { for(int j=1;j<=n;j++) printf("%d ",c[j]); } return 0; } /* 5 1 2 3 4 3 1 2 5 4 5 5 5 4 5 3 1 4 4 2 3 1 */