STEP 1:分析
题目大意:给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。
这一题一眼看出是 P2010 的升级版,所以要先考虑到超时问题,因为如果一天一天地枚举,时间复杂度会非常高,所以我们不能直接枚举。因为题目只要"回文",所以我们只要一个个扫描年份,再根据年份的反转数得到日期,并判断得出的日期是否合法,记得闰年特判,就能得出答案了。
STEP 2:构建
判断闰年函数
bool rn(int yy) { return (yy % 400 == 0) || (yy % 4 == 0 && yy % 100 != 0); }
|
构建反转函数
int rev(int x) { int sum; for (sum = 0; x; x /= 10) sum = sum * 10 + x % 10; return sum; }
|
构建两种判断
这里需要注意:
- 要判断闰年
- 不能算错日期
这里有两种判断(普通回文日期和 ABABBABA 型日期),可以试着利用普通回文日期的判断减少 ABABBABA 型日期判断的码量。
bool check(int yy) { if (rn(yy)) mon[2] = 29; else mon[2] = 28; int mm = (yy % 10) * 10 + (yy / 10 % 10); int dd = (yy / 100 % 10) * 10 + (yy / 1000); return mm >= 1 && mm <= 12 && dd >= 1 && dd <= mon[mm]; }
|
bool ABABBABA(int yy) { return check(yy) && (yy % 10 == yy / 100 % 10) && (yy / 10 % 10 == yy / 1000); }
|
主函数
在主函数里,有一个非常重要的环节:特判当前年份有没有这两个种类的回文日期,因为不是按日期枚举,所以无法从给定的日期开始枚举,那么就需要特判。
cin >> n; yy = n / 10000; mm = n / 100 % 100; dd = n % 100; int dt = rev(yy), dmm = dt / 100 % 100, ddd = dt % 100; if (ABABBABA(yy) && (dmm > mm || (dmm == mm && ddd > dd))) { check2 = yy; } if (check(yy) && (dmm > mm || (dmm == mm && ddd > dd))) { check1 = yy; }
|
好了,最后我们只要枚举以后的年份,直到找到答案。
for (int i = yy + 1; ; i++) { if (check1 != -1 && check2 != -1) break; if (ABABBABA(i) && check2 == -1) check2 = i; if (check(i) && check1 == -1) check1 = i; } printf("%04d%04d\n%04d%04d", check1, rev(check1), check2, rev(check2));
|
所有的步骤都分析完了,请读者自行完成完整代码~\ 制作不易,希望这篇题解能有些用处