暑假考试题5:序列(分类讨论水题)

题目:

排列指的是值域连续的(从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
*/
原文地址:https://www.cnblogs.com/mowanying/p/11414381.html