专栏文章

题解:P14042 [SDCPC 2019] Calandar

P14042题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minvmo15
此快照首次捕获于
2025/12/02 09:05
3 个月前
此快照最后确认于
2025/12/02 09:05
3 个月前
查看原文

题意

给定两个年月日日期以及第一个日期的星期数,求第二个年月日是星期几。(3030 天一个月,一周五天)

思路

求第二个日期的星期数,需要先求出两个日期之间相差的天数,然后用天数对 55 取模求出星期数。
如果考虑暴力,从第一个日期开始往后算,由于年份最大为 10910^9,所以超时的风险很大。
事实上,想要计算相差的天数可以简化计算过程:
  • 对于月份相同的两个日期,相差的天数即为 d2d1d_2 - d_1
  • 对于月份不同但年份相同的两个日期,可以先计算两个月之间度过了完整一个月的月份数为 (m21)(m1+1)+1=m2m11(m_2 - 1) - (m_1 + 1) + 1 = m_2 - m_1 - 1,将这个数乘 3030 就是这几个月度过的天数。再将两端点月份剩下的天数加起来,左端点月份度过的天数为 31d11=30d131 - d_1 - 1 = 30 - d_1,右端点月份度过的天数为 d2d_2。因此总天数为 d2+(30d1)+30(m2m11)d_2 + (30 - d_1) + 30(m_2 - m_1 - 1)
  • 对于年份不同的两个日期,先算度过了完整的年份数为 y2y11y_2 - y_1 - 1,由于一年有 30×12=36030 \times 12 = 360 天,所以该数乘 360360 即这几年度过的天数。再算两端点年份中度过完整月份的月份数,左端点完整月份数为 12(m1+1)+1=11m112 - (m_1 + 1) + 1 = 11 - m_1,右端点完整月份数为 m21m_2 - 1,总共就是 10m1+m210 - m_1 + m_2,再按上述同理算出剩下的天数。因此总天数为 d2+(30d1)+30(10m1+m2)+360(y2y11)d_2 + (30 - d_1) + 30(10 - m_1 + m_2) + 360(y_2 - y_1 - 1)
算完天数,将当前星期数加上天数,对 55 取模,即可得到最终的星期数。
但还没完,我们观察样例发现有下面这样的数据:
CPP
1000000000 1 1 Wednesday
2019 5 12
前面的日期要比后面的日期要晚,想解决也很简单,首先判断年份是否晚于后者,如果年份相同那么判断月份,月份相同再判断天数即可。
如果前者晚于后者,可以使用 swap 函数将年月日两个数据交换。同时还要注意,我们最后算星期数的时候还需要从晚到早数,因此算出的天数之差需要取相反数再取模。

Code

CPP
#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 不在,我把这个代码修改了一下。
因此你是不能通过复制粘贴这个代码来通过本题的。
祝你好运^ ^
*/

评论

0 条评论,欢迎与作者交流。

正在加载评论...