LQ0150 回文日期枚举

Posted 海岛Blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LQ0150 回文日期枚举相关的知识,希望对你有一定的参考价值。

题目来源:蓝桥杯2020初赛 C++ A组G题

题目描述
2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。

有人表示 20200202 是 “千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。

也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。算不上 “千年一遇”,顶多算 “千年两遇”。

给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。

输入描述
输入包含一个八位整数 N,表示日期。

对于所有评测用例,10000101≤N≤89991231,保证 N 是一个合法日期的 8 位数表示。

输出描述
输出两行,每行 1 个八位数。第一行表示下一个回文日期,第二行表示下一个 ABABBABA 型的回文日期。

输入输出样例
输入
20200202
输出
20211202
21211212

问题分析
这个题蓝桥杯官网的测试数据有BUG,N的最大值应该是99991231而不是89991231,否则AC不了。
一种方法是暴力法,速度比较慢。枚举的日期从N+1到99991231。
另外一种是根据约束条件进行枚举,月份的第1位只能是0或1。而年的最后一位对应月份的第1位,枚举年的话,只需要考虑年的最后1位是0或1,枚举的数量就少多了。
有T个输入的情形(网站http://oj.ecustacm.cn/),用后一种解法改造后可以通过,不会出现TLE(超时)。这里也给出有关的题解。

AC的C语言程序(枚举年)如下:

/* LQ0150 回文日期 */

#include <stdio.h>

int mdays[] = 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31;

int judge(int y, int m, int d)

    if (1 <= m && m <= 12) 
        int md = mdays[m];
        if (m == 2)
            md += (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
        if (1 <= d && d <= md)
            return 1;
    
    return 0;


int reverse(int n)

    int ret = 0;
    for (int i = 1; i <= 4; i++)
        ret *= 10, ret += n % 10, n /= 10;
    return ret;


int main()

    int n;
    scanf("%d", &n);

    int year = n / 10000, date1 = 0, date2 = 0;
    for (int y = (year / 10) * 10; y <= 9999; y += 10) 
        int md = reverse(y);
        if (y * 10000 + md > n) 
            int month = md / 100;
            int day = md % 100;
            if (judge(y, month, day)) 
                if (date1 == 0) date1 = y * 10000 + md;
                if (date2 == 0 && month == day) date2 = y * 10000 + md;
                if (date1 && date2) break;
            
        

        int y1 = y + 1;
        md = reverse(y1);
        if (y1 * 10000 + md > n) 
            int month = md / 100;
            int day = md % 100;
            if (judge(y1, month, day)) 
                if (date1 == 0) date1 = y1 * 10000 + md;
                if (date2 == 0 && month == day) date2 = y1 * 10000 + md;
                if (date1 && date2) break;
            
        
    

    printf("%08d\\n%08d\\n", date1, date2);

    return 0;

AC的C语言程序(多输入)如下:

/* LQ0150 回文日期 */

#include <stdio.h>

int mdays[] = 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31;

int judge(int y, int m, int d)

    if (1 <= m && m <= 12) 
        int md = mdays[m];
        if (m == 2)
            md += (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
        if (1 <= d && d <= md)
            return 1;
    
    return 0;


int reverse(int n)

    int ret = 0;
    for (int i = 1; i <= 4; i++)
        ret *= 10, ret += n % 10, n /= 10;
    return ret;


int main()

    int t, n;
    scanf("%d", &t);
    while (t--) 
        scanf("%d", &n);
    
        int year = n / 10000, date1 = 0, date2 = 0;
        for (int y = (year / 10) * 10; y <= 9999; y += 10) 
            int md = reverse(y);
            if (y * 10000 + md > n) 
                int month = md / 100;
                int day = md % 100;
                if (judge(y, month, day)) 
                    if (date1 == 0) date1 = y * 10000 + md;
                    if (date2 == 0 && month == day) date2 = y * 10000 + md;
                    if (date1 && date2) break;
                
            
    
            int y1 = y + 1;
            md = reverse(y1);
            if (y1 * 10000 + md > n) 
                int month = md / 100;
                int day = md % 100;
                if (judge(y1, month, day)) 
                    if (date1 == 0) date1 = y1 * 10000 + md;
                    if (date2 == 0 && month == day) date2 = y1 * 10000 + md;
                    if (date1 && date2) break;
                
            
        
    
        printf("%08d\\n%08d\\n", date1, date2);
    

    return 0;

AC的C语言程序(简单暴力)如下:

/* LQ0150 回文日期 */

#include <stdio.h>

int mdays[] = 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31;

int judge(int y, int m, int d)

    if (1 <= m && m <= 12) 
        int md = mdays[m];
        if (m == 2)
            md += (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
        if (1 <= d && d <= md)
            return 1;
    
    return 0;


int reverse(int n)

    int ret = 0;
    for (int i = 1; i <= 4; i++)
        ret *= 10, ret += n % 10, n /= 10;
    return ret;


int main()

    int n;
    scanf("%d", &n);

    int date1 = 0, date2 = 0;
    for (int i = n + 1; i <= 99991231; i++) 
        int md = i % 10000;
        int year = i / 10000;
        int month = md / 100;
        int day = md % 100;
        if (judge(year, month, day) && md == reverse(year)) 
            if (date1 == 0) date1 = i;
            if (date2 == 0 && month == day) date2 = i;
        
        if (date1 && date2) break;
    

    printf("%08d\\n%08d\\n", date1, date2);

    return 0;

以上是关于LQ0150 回文日期枚举的主要内容,如果未能解决你的问题,请参考以下文章

Python案例:输出指定要求的回文日期

回文日期 (蓝桥云) JAVA

小学生蓝桥杯Python闯关 | 回文日期

LQ0018 顺子日期枚举+日期

LQ0018 顺子日期枚举+日期

LQ0090 山枚举