题解 P2010 【回文日期】
已注销kmP36Yzp · · 题解
这个题目已经非常宽容了,如果你掌握了回文数的计算方法,你至少能得 60 分,当然看完这篇文章你就可以得 100 分了。(awa
那就直入主题吧,每个题目都可能有多种解法,你选择的切入点决定了你使用的解法的复杂度。对这个题来说,枚举是免不了的,重点是怎么枚举。
枚举年
区间内的年比较少,对于某一年来说,比如 2019,我们只需要判断 9102 是否是合法的月和日就行了。
在这个思想的指引下,先把两个日期中间的所有年筛选出来,同时求出年份的回文数。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int date1,date2,year1,year2;
cin >> date1 >> date2;
year1 = date1 / 10000;
year2 = date2 / 10000;
//遍历范围内的所有年份
for(int year = year1;year<=year2;year++) {
}
return 0;
}
顺着这个思路,主要的任务是根据 year 求出完整的当前year的回文日期,比如命名为 aim_year ,写出的完整代码如下
#include <bits/stdc++.h>
using namespace std;
int main()
{
//变量着实是有点多
int date1,date2,year1,year2,fan_year,aim_date,tmp_year,month,day,cnt=0;
// 2月份直接用 29 天,因为0229反过来9220,9220是闰年,满足题意
int days[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31};
cin >> date1 >> date2;
year1 = date1 / 10000;
year2 = date2 / 10000;
//遍历范围内的所有年份
for(int year = year1;year<=year2;year++) {
//生成回文年的时候不能直接修改year,所以用临时变量tmp_year
tmp_year = year;
fan_year = 0;
//先生成年的回文年
for(int i = 1;i<=4;i++) {
fan_year = tmp_year%10 + fan_year*10;
tmp_year /= 10;
}
//把回文年拆成月和日
month = fan_year/100;
day = fan_year%100;
//aim_date 是组合出的当前年份的完整回文日期
aim_date = year*10000+month*100+day;
//月份得合法,日得合法,同时生成的回文日期得在给定的范围内
if(month <= 12 && month>=1 && day <= days[month] && aim_date >=date1 && aim_date <= date2){
cnt++;
}
}
cout<<cnt;
return 0;
}
枚举月和日
另一种方法是直接枚举合法的月和日,组成所有回文日期,判断完整的日期是否在给定的日期范围内即可。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int date1,date2,fan_year,tmp_year,year,aim_date,cnt=0;
int days[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};
cin>>date1>>date2;
//枚举所有合法的月和日
for (int month=1;month<=12;month++)
for (int day =1;day<=days[month];day++)
{
fan_year= month*100+day;
tmp_year = fan_year;
year = 0;
//根据回文年生成原本的年
for(int i = 1;i<=4;i++) {
year = tmp_year%10 + year*10;
tmp_year /= 10;
}
//生成完整的回文日期
aim_date = year*10000 + fan_year;
//好处是这次不用判断月和日是否合法了
if(aim_date >= date1 && aim_date <= date2)
cnt++;
}
cout<<cnt;
return 0;
}
通过对比可以发现,枚举年的时候只有一层循环,但是判断条件复杂,枚举月日时需要写嵌套循环,但是条件简单。