题目描述
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 型的回文日期。
实现代码
#include<bits/stdc++.h>
using namespace std;
int month[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int main()
{
// 给 yyyymmdd,找出下一个ABCDDCBA型,下一个ABABBABA型
int yy,mm,dd;
// char input[8]={0};
// for(int i=0;i<8;i++)
// {
// cin>>input[i];
// }
// sscanf(input,"%4d %2d %2d",&yy,&mm,&dd); // 注意后面的 & 符号
scanf("%4d %2d %2d",&yy,&mm,&dd); // 这个直接把输入放到想要的地方里
//cout<<yy<<"-"<<mm<<"-"<<dd<<endl;
int next_ABCD_yy,next_ABCD_mm,next_ABCD_dd; // 下一个ABCDDCBA回文
for(int i=yy;;i++)
{
next_ABCD_yy=i;
next_ABCD_mm=next_ABCD_yy%10*10 + next_ABCD_yy/10%10; //倒数第一位*10+倒数第二位 2021取12 2149 9412
next_ABCD_dd=next_ABCD_yy/100%10*10 +next_ABCD_yy/1000; //倒数第三位*10+倒数第四位 2021取02
// 比如 21210101 ,下一次ABAB型应该是21211212,但是年加一以后就很远
if(next_ABCD_yy==yy&&next_ABCD_mm==mm&&next_ABCD_dd==dd)
{
continue;
}
// 如果月份大于12或者小于1 或者 日期大于本月最大日子或者小于1,就继续
if(next_ABCD_mm>12||next_ABCD_mm<1||next_ABCD_dd<1||next_ABCD_dd>month[next_ABCD_mm])
{
continue;
}
cout<<next_ABCD_yy;
cout<<setw(2)<<setfill('0')<<next_ABCD_mm;
cout<<setw(2)<<setfill('0')<<next_ABCD_dd<<endl;
break;
}
int next_ABAB_yy,next_ABAB_mm,next_ABAB_dd; // 下一个ABAB BABA回文
for(int i=yy;;i++)
{
next_ABAB_yy=i;
next_ABAB_mm=next_ABAB_yy%10*10 + next_ABAB_yy/10%10; //倒数第一位*10+倒数第二位 2021取12 2149 9412
next_ABAB_dd=next_ABAB_yy/100%10*10 +next_ABAB_yy/1000; //倒数第三位*10+倒数第四位 2021取02
// 如果 ABCD 反过来,DC不等于BA,那么证明AB不等于CD,不满足ABAB
// 比如 2021 反过来 12 和 02不等,证明 2021不是ABAB型
if(next_ABAB_dd!=next_ABAB_mm)
{
continue;
}
// 比如 21210101 ,下一次ABAB型应该是21211212,但是年加一以后就很远
if(next_ABAB_yy==yy&&next_ABAB_mm==mm&&next_ABAB_dd==dd)
{
continue;
}
// 如果月份大于12或者小于1 或者 日期大于本月最大日子或者小于1,就继续
if(next_ABAB_mm>12||next_ABAB_mm<1||next_ABCD_dd<1||next_ABCD_dd>month[next_ABAB_mm])
{
continue;
}
cout<<next_ABAB_yy;
cout<<setw(2)<<setfill('0')<<next_ABAB_mm;
cout<<setw(2)<<setfill('0')<<next_ABAB_dd<<endl;
break;
}
}
解题思路
只要碰到有年月日的题,首先把每个月的天数存到数组里后面备用。然后把输入的东西分别存到年月日里面,方便后面操作。
先找第一个 ABCDDCBA 回文,直接放循环里面,把需要比较的位通过算数存起来,后面比一下就行,还需要对每月的天数进行限制,然后输出,注意输出的时候需要保持格式一致。
下一个 ABABBABA 回文和这个类似,需要注意的是 for 循环的条件,定义从输入的这一年开始,如果从下一年开始,如果输入21210101,类似 21211212 这样的就会被略去,从 2122 年开始找,所以需要加一个判断,如果输入的这个就是 ABABBABA 型的,就找下一个,不会出现因为在同一年就被忽略的情况。
注意点
- 首先注意固定格式输出,在前面说过,
cout<<setw(2)<<setfill('0')<<next_ABAB_dd<<endl;
这样就可以输出想要的位数,如果有空位填充字符是什么。 - 其次注意 for 循环不要从下一年开始,因为本年可能会出现答案,所以要加一点判断。
知识点
- 输出固定位数:
cout<<setw(2)<<setfill('0')<<next_ABAB_dd<<endl;
- 函数
sscanf
和scanf
,注意不同之处。出现年月日这一类,就存到设好的变量里面。有两种把输入的东西存进给定变量的方法。
// 1
char input[8]={0};
for(int i=0;i<8;i++)
{
cin>>input[i];
}
sscanf(input,"%4d %2d %2d",&yy,&mm,&dd); // 注意后面的 & 符号
// 2
scanf("%4d %2d %2d",&yy,&mm,&dd); // 这个直接把输入放到想要的地方里