LuoguP1202 [USACO1.1]黑色星期五Friday the Thirteenth 题解
真·模拟水题,注意细节。
细节是什么?能吃吗?
首先最主要的还是处理闰年这个问题,我们先回去看题目,其中的第3、4个你要知道的就很好地讲明了处理闰年的规则:
年份可以被\(4\)整除的为闰年(\(1992=4*498\) 所以 \(1992\)年是闰年,但是\(1990\)年不是闰年)。
以上规则不适合于世纪年(即能被\(100\)整除的年份——作者注)。可以被400整除的世纪年为闰年,否则为平年。所以,\(1700,1800,1900\)和\(2100\)年是平年,而\(2000\)年是闰年。
所以我们可以想出这样一个判断闰年的过程:
\(Step~1:\)判断是否是世纪年。如果是的话,判断是否能被\(400\)整除,是则该年份是闰年,否则不是。
\(Step~2:\)否则,判断完该年份不是世纪年之后,只需要看其是否能被\(4\)整除,是则该年份是闰年,否则不是。
至此,如下的年份判断程序就很清晰明了了:
bool check(int n) {
if(n % 100 == 0) {
if(n % 400 == 0) return 1;
return 0;
}
if(n % 4 == 0) return 1;
return 0;
}
这段打完之后,另外的问题又扑面而来:如何转换日期呢?
首先,我们知道这道题目给我们的初始日期为\(1900\)年\(1\)月\(1\)日星期一。其次,我们再回看题目:
\(2,4,6,11\)和\(9\)月有30天.其他月份除了\(2\)月都有\(31\)天.闰年\(2\)月有\(29\)天,平年\(2\)月有\(28\)天。
我们都知道,从本月末到下月初,月份要加\(1\),天份要归\(1\)。从今年末到明年初,年份要加\(1\),月份和天份都归\(1\)。星期数到了\(7\),下一天也要归\(1\)。
所以,我们想到了如下的转换日期程序:
\(Step~1:\)从\(1900\)年\(1\)月\(1\)日星期一开始!
\(Step~2:\)如果一切正常,天份加\(1\),星期数也加\(1\)。
\(Step~3:\)如果到了星期末,就要将星期数及时归\(1\)。
\(Step~4:\)如果到了月末,月份就要加\(1\),天份同时要归\(1\)。
\(Step~5:\)在执行\(Step~4\)的时候,如果还到了年末,年份加\(1\),月份和天份同时归\(1\)。
程序也很明了了吧,自己先打代码,若有困难再看以下代码:
while(y <= 1900 + n - 1) {
// printf("%d/%d/%d %d\n", y, m, d, week);
// y是年份,m是月份,d是天份,week是星期数
// ans[i]指对应星期数13日出现的次数
if(d == 13) ans[week]++;
week++;
if(week > 7) week = 1;
d++;
if(d > (m == 2 ? (check(y) ? f[m] + 1 : f[m]) : f[m])) {
m++;
d = 1;
}
if(m > 12) {
y++;
m = 1;
}
}
输出就没什么好讲的,可以暴力输出,可以用两个循环输出,还可以用各种奇葩的方法输出。反正随你们便。
下面贴完整代码:
#include <cstdio>
#include <algorithm>
using namespace std;
inline int read() {
int f = 1, x = 0;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
const int f[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int y = 1900, m = 1, d = 1, n, week = 1;
int ans[7];
bool check(int n) {
if(n % 100 == 0) {
if(n % 400 == 0) return 1;
return 0;
}
if(n % 4 == 0) return 1;
return 0;
}
int main() {
n = read();
while(y <= 1900 + n - 1) {
// printf("%d/%d/%d %d\n", y, m, d, week);
if(d == 13) ans[week]++;
week++;
if(week > 7) week = 1;
d++;
if(d > (m == 2 ? (check(y) ? f[m] + 1 : f[m]) : f[m])) {
m++;
d = 1;
}
if(m > 12) {
y++;
m = 1;
}
}
for(int i = 6; i <= 7; ++i)
printf("%d ", ans[i]);
for(int i = 1; i <= 5; ++i)
printf("%d ", ans[i]);
return 0;
}

浙公网安备 33010602011771号