题目
小蓝每天都锻炼身体。
正常情况下,小蓝每天跑 1 千米。如果某天是周一或者月初(1 日),为了激励自己,小蓝要跑 2 千米。如果同时是周一或月初,小蓝也是跑 2 千米。小蓝跑步已经坚持了很长时间,从 2000 年 1 月 1 日周六(含)到 2020 年10 月 1 日周四(含)。请问这段时间小蓝总共跑步多少千米?
思路
我们首先写一个判断日期是否合法的函数
check
,这个函数用来检查一个八位的日期是否合法。
模板如下
int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool check(int date)
{
int year = date / 10000; //年
int month = date % 10000 / 100; //月
int day = date % 100; //日
if(!month || month > 12 || !day ) return false;//如果月份大于12或者为零或者天数为零则该日期不合法
if(month != 2 && day > months[month]) return false;//在不是二月的情况下,该月实际天数大于该月最大天数,则该日期不合法
if(month == 2) //特判二月
{
if((year % 4 == 0&& year % 100 != 0) || (year % 400 == 0))//特判闰年
{
if(day > 29) return false;
}
else if( day > 28) return false;
}
return true;
}
这个模板要牢记,几乎可以套所有的日期模拟题,尤其对这种填空题,可以说是大杀器。
然后我们枚举日期
20000101
到日期
20201001
,筛选出合法的日期。这里有一个难点,如何判断某一天是星期几?其实我们可以发现星期几是和这天是几号无关的,因为一周七天,每七天一轮回,该天是星期几取决于起始日期是星期几和该天离起始日期多少天。假设终点日期离起始日期
sum
天,起始日期是星期六,我们只需
(sum + 6) % 7 == 1
就可以轻松判断出这天是不是星期一。
(sum + 6) % 7 == 0
代表星期日,其余一 一对应。我们带一个特殊日期验证一下,假设终点日期是起始日期,
sum==0
,
(0 + 6) % 7 == 6
,验证无误,当然如果不放心的话可以多带几个日期验证一下。
答案: 8879
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool check(int date)
{
int year = date / 10000;
int month = date % 10000 / 100;
int day = date % 100;
if(!month || month > 12 || !day ) return false;//
if(month != 2 && day > months[month]) return false;
if(month == 2)
{
if((year % 4 == 0&& year % 100 != 0) || (year % 400 == 0))
{
if(day > 29) return false;
}
else if( day > 28) return false;
}
return true;
}
int main()
{
int res = 0,sum = 0;//sum记录相隔天数,res记录答案
for(int i = 20000101; i <= 20201001; i++) // 1 2 3
{
if(check(i))
{
res ++ ;
int month = i % 10000 / 100;
int day = i % 100;
if( day == 1 || (sum + 6) % 7 == 1 ) res++; //周一或月初,加一千米
sum ++ ;
}
}
cout<<res<<endl;
return 0;
}