CCF 201503-3 节日 传送门
一道日期相关的题目, 用Zeller公式可简化过程.
思路就是通过Zeller公式获得某一年得m月1日的星期, 再根据这个星期获取该月份的第th个星期w的天数.
Zeller公式: (c/4 - 2*c + y + y/4 + 13*(m + 1)/5 + d - 1)mod7
但要注意的是此公式有几个坑! 那就是1月2月要当作上一年的13月14月来看.但不是简单的month +12
, 而是上一年! year要减一! 以为这就完了? 错, 如果遇到2000
年这种情况, 世纪也要减一! 还有取模得结果可能是负数, 要做下特殊判断.
还有要注意的是: 每一次遍历年份的时候, 2月份的天数都要重置为28
. 这个坑了我好久
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int Zeller(int year, int mon, int day)
{
if (mon <= 2)
year--, mon += 12;
int cent = year / 100;
year %= 100;
int week = (year/4 + year + cent/4 - 2*cent + 13*(mon + 1)/5 + day - 1);
return week % 7;
}
int main()
{
int mon, th, weekday, start, end;
cin >> mon >> th >> weekday >> start >> end;
int month[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
for (int year = start; year <= end; ++year) {
month[2] = 28; // 靠, 前面是闰年之后还要回到不是闰年的!!!
if (year % 400 == 0 || (year % 4 == 0 && year % 100))
month[2] = 29;
int wd = Zeller(year, mon, 1), day;
wd = wd > 0 ? wd : wd + 7;
if (wd == weekday) {
day = (th - 1)*7;
} else {
wd = wd < weekday ? wd : wd - 7;
day = (th - 1)*7 + weekday - wd;
}
if (day + 1 <= month[mon]) {
printf("%04d/%02d/%02d\n", year, mon, day + 1);
} else cout << "none" << endl;
}
}