Luogu P8651 题解

发布时间 2023-10-05 15:40:01作者: I_like_magic

这是让我最崩溃的一道橙题了。

整整 11 次提交才 AC。

这道题有几个要点必须注意:

  • 判断日期是否合理。

  • 按顺序输出。

  • 判断重复的日期。


首先,我们来看怎么判断日期是否合理。

我们知道大月有 \(31\) 天,小月有 \(30\) 天,二月看平年闰年。

所以,我们可以写出这样的代码:

bool check(int y,int m,int d){
    if(d<=0)return 0;//特判
    if(m==1||m==3||m==5||m==7||m==8||m==10||m==12){//大月
        if(d<=31)return 1;
    }
    if(m==4||m==6||m==9||m==11){//小月
        if(d<=30)return 1;
    }
    if(m==2){//二月
        if(y%4==0){//闰年
            if(d<=29)return 1;
        }else{//平年
            if(d<=28)return 1;
        }
    }
    return 0;
}

接下来,我们需要按顺序输出日期。

我们发现,只有 \(A\)\(C\) 会做年份,此时只要判断 \(A\)\(C\) 哪一年更早即可。

接下来,如果年份相同,那么看月,所以比较 \(A\)\(B\) 哪个更早。

我的输出是放在函数 void out(int n); 里面的,其中 \(n\)\(1,2,3\) 中的一数,表示三种格式。

注意判断年份是 \(19\) 开头还是 \(20\) 开头,并且日期和月份不足两位要输出前导零。

void out(int n){//输出
    switch(n){
        case 1:{//年月日
            if(check(a,b,c)){
                printf("%d%02d-%02d-%02d\n",a>=60?19:20,a,b,c);
            }
            break;// break 很重要
        }
        case 2:{//月日年
            if(check(c,a,b)){
                printf("%d%02d-%02d-%02d\n",c>=60?19:20,c,a,b);
            }
            break;
        }
        case 3:{//日月年
            if(check(c,b,a)){
                printf("%d%02d-%02d-%02d\n",c>=60?19:20,c,b,a);
            }
            break;
        }
    }
}
signed main(){
    scanf("%d/%d/%d",&a,&b,&c);//输入
    if(a<60)a+=100;
    if(c<60)c+=100;//年份小于 60 要加上 100
    if(a<c){//年份比较大小
        a%=100;
        c%=100;//变回原来的样子
        out(1);
        if(a<b){
            if(c!=a||a!=b||b!=c){//判断重复!!!
                out(2);
                if(b!=a)out(3);
            }
        }else{
            if(c!=a){
                out(3);
                if(b!=a)out(2);
            }
            
        }
    }else{//下面和上面一个道理
        a%=100;
        c%=100;
        if(a<b){
            if(c!=a||a!=b||b!=c){
                out(2);
                if(b!=a)out(3);
            }
        }else{
            if(c!=a){
                out(3);
                if(b!=a)out(2);
            }
        }
        out(1);
    }
    return 0;
}

还有一点也很重要,记得判断重复的日期。

比如输入为 01/01/00 时,你的代码很可能输出两个 2000-01-01,这样会 WA。

判重请看上面的代码理解一下。


AC Code:

#include<iostream>
using namespace std;
int a,b,c;
bool check(int y,int m,int d){
    if(d<=0)return 0;//特判
    if(m==1||m==3||m==5||m==7||m==8||m==10||m==12){//大月
        if(d<=31)return 1;
    }
    if(m==4||m==6||m==9||m==11){//小月
        if(d<=30)return 1;
    }
    if(m==2){//二月
        if(y%4==0){//闰年
            if(d<=29)return 1;
        }else{//平年
            if(d<=28)return 1;
        }
    }
    return 0;
}
void out(int n){//输出
    switch(n){
        case 1:{//年月日
            if(check(a,b,c)){
                printf("%d%02d-%02d-%02d\n",a>=60?19:20,a,b,c);
            }
            break;// break 很重要
        }
        case 2:{//月日年
            if(check(c,a,b)){
                printf("%d%02d-%02d-%02d\n",c>=60?19:20,c,a,b);
            }
            break;
        }
        case 3:{//日月年
            if(check(c,b,a)){
                printf("%d%02d-%02d-%02d\n",c>=60?19:20,c,b,a);
            }
            break;
        }
    }
}
signed main(){
    scanf("%d/%d/%d",&a,&b,&c);//输入
    if(a<60)a+=100;
    if(c<60)c+=100;//年份小于 60 要加上 100
    if(a<c){//年份比较大小
        a%=100;
        c%=100;//变回原来的样子
        out(1);
        if(a<b){
            if(c!=a||a!=b||b!=c){//判断重复!!!
                out(2);
                if(b!=a)out(3);
            }
        }else{
            if(c!=a){
                out(3);
                if(b!=a)out(2);
            }
            
        }
    }else{//下面和上面一个道理
        a%=100;
        c%=100;
        if(a<b){
            if(c!=a||a!=b||b!=c){
                out(2);
                if(b!=a)out(3);
            }
        }else{
            if(c!=a){
                out(3);
                if(b!=a)out(2);
            }
        }
        out(1);
    }
    return 0;
}