题解:P14042 [SDCPC 2019] Calandar
题意
给定两个年月日日期以及第一个日期的星期数,求第二个年月日是星期几。(
思路
求第二个日期的星期数,需要先求出两个日期之间相差的天数,然后用天数对
如果考虑暴力,从第一个日期开始往后算,由于年份最大为
事实上,想要计算相差的天数可以简化计算过程:
- 对于月份相同的两个日期,相差的天数即为
d_2 - d_1 。 - 对于月份不同但年份相同的两个日期,可以先计算两个月之间度过了完整一个月的月份数为
(m_2 - 1) - (m_1 + 1) + 1 = m_2 - m_1 - 1 ,将这个数乘30 就是这几个月度过的天数。再将两端点月份剩下的天数加起来,左端点月份度过的天数为31 - d_1 - 1 = 30 - d_1 ,右端点月份度过的天数为d_2 。因此总天数为d_2 + (30 - d_1) + 30(m_2 - m_1 - 1) 。 -
对于年份不同的两个日期,先算度过了完整的年份数为
y_2 - y_1 - 1 ,由于一年有30 \times 12 = 360 天,所以该数乘360 即这几年度过的天数。再算两端点年份中度过完整月份的月份数,左端点完整月份数为12 - (m_1 + 1) + 1 = 11 - m_1 ,右端点完整月份数为m_2 - 1 ,总共就是10 - m_1 + m_2 ,再按上述同理算出剩下的天数。因此总天数为d_2 + (30 - d_1) + 30(10 - m_1 + m_2) + 360(y_2 - y_1 - 1) 。算完天数,将当前星期数加上天数,对
5 取模,即可得到最终的星期数。但还没完,我们观察样例发现有下面这样的数据:
1000000000 1 1 Wednesday 2019 5 12前面的日期要比后面的日期要晚,想解决也很简单,首先判断年份是否晚于后者,如果年份相同那么判断月份,月份相同再判断天数即可。
如果前者晚于后者,可以使用
swap函数将年月日两个数据交换。同时还要注意,我们最后算星期数的时候还需要从晚到早数,因此算出的天数之差需要取相反数再取模。
Code
#include <iostream>
#include <cstdio>
#include <string>
#include <cmath>
using namespace std;
typedef long long ll;
ll t, y1, m1, d1, y2, m2, d2, del, wkn;
string wk;
bool checkswp(){ // 检查日期是否需要交换
if(y1 > y2) return true;
if(y1 == y2 && m1 > m2) return true;
if(y1 == y2 && m1 == m2 && d1 > d2) return true;
return false;
}
void swp(){ // 交换日期
swap(y1, y2);
swap(m1, m2);
swap(d1, d2);
return ;
}
ll gabs(ll x){ // 获取取模结果
return ((x >= 0LL) ? x : (x + 5)); // 负数取模需要加上除数
}
int main()
{
scanf("%lld", &t);
while(t--){
scanf("%lld%lld%lld", &y1, &m1, &d1);
cin >> wk;
// 获取日期
if(wk == "Monday") wkn = 0LL;
else if(wk == "Tuesday") wkn = 1LL;
else if(wk == "Wednesday") wkn = 2LL;
else if(wk == "Thursday") wkn = 3LL;
else if(wk == "Friday") wkn = 4LL;
scanf("%lld%lld%lld", &y2, &m2, &d2);
// 交换日期
bool ifswp = checkswp();
if(ifswp) swp();
// 求差值
if(m1 == m2) del = d2 - d1;
else{
ll tmp;
if(y1 == y2) tmp = (m2 - m1 - 1LL) * 30LL;
else tmp = (10 - m1 + m2) * 30LL + (y2 - y1 - 1LL) * 360LL;
del = d2 + 30LL - d1 + tmp;
}
if(ifswp) del = -del;
wkn = gabs((wkn + del) % 5LL); // 计算日期
// 输出
switch(wkn){
case 0LL:
puts("Monday");
break;
case 1LL:
puts("Tuesday");
break;
case 2LL:
puts("Wednesday");
break;
case 3LL:
puts("Thursday");
break;
case 4LL:
puts("Friday");
break;
}
}
return 0; // 结束 (。・ω・。)
}
/*
你好啊,我是 vzAczA。
趁 UNNN 不在,我把这个代码修改了一下。
因此你是不能通过复制粘贴这个代码来通过本题的。
祝你好运^ ^
*/