P8831 [传智杯 #3 练习赛] 儒略历 题解
调了半天终于对了(
Step 1: 读入
如题我们已知输入的格式是 日 月 年 ,而月是用字符串表示,所以我们需要把哪一月份给求出来。
根据题目给的缩写,我们就可以打表来计算月份。
string month[13]={"","JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"};
由于我们读入的是个字符串,所以我们紧接着还要把年和日求出来,先求日,再求年。
把字符串转化成数字这应该人人皆知如何处理,这里不做细讲。我们先把前面的数字给日,直到出现了字符,我们之后出现的数字才给年。
for(int i=0;i<st.size();i++){
if(st[i]>='0'&&st[i]<='9'){
if(!ok)d*=10,d+=int(st[i]-48ll);//在出现字符之前计算日。
else y*=10,y+=int(st[i]-48ll);//在出现字符后计算年。
}
else mon+=st[i],ok=1;//ok 代表是否出现了字符,mon最终是月份的字符串。
}
别问我为什么是减去 48ll ,只是防止 ctjer。
把月份化成数字也就很方便了。
for(int i=1;i<=12;i++)
if(mon==month[i]){//正好匹配到一样的月份,i 的值即为月份。
m=i;
break;
}
Step 2: 计算天数
题目由此可以化简为:我们已知现在是 y 年 m 月 d 日,求离 1 年 1 月 1 日多少天。
显然的,y 年不一定过完了,m 月也不一定过完了,所以我们不能直接加到它们的值,而是要到它们的值 -1。
由题我们又可以把月份分成3种情况:
- 年
\lt 1582 ,闰年只需判断是否能被 4 整除。 - 年
= 1582 ,不是闰年,10 月少了 10 天。 - 年
\gt 1582 ,闰年包括普通和世纪闰年。
普通闰年:能被 4 整除不能被 100 整除。
世纪闰年:能被 400 整除。
拓展芝士:闰秒将在2035年取消。
根据上述条件,我们也就可以得出代码啦。
代码如下:
#include<bits/stdc++.h>
using namespace std;
string month[13]={"","JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"};
int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};//每个月的天数
signed main()
{
int d=0,m=0,y=0;
string st,mon="";
bool ok=0;
cin>>st;
for(int i=0;i<st.size();i++){
if(st[i]>='0'&&st[i]<='9'){
if(!ok)d*=10,d+=int(st[i]-48ll);//在出现字符之前计算日。
else y*=10,y+=int(st[i]-48ll);//在出现字符之前计算年。
}
else mon+=st[i],ok=1;//ok 代表是否出现了字符,mon最终是月份的字符串。
}
for(int i=1;i<=12;i++)
if(mon==month[i]){//正好匹配到一样的月份,i 的值即为月份。
m=i;
break;
}
//cout<<y<<' '<<m<<' '<<d<<'\n';
if(y<1582)a[2]=(y%4==0?29:28);;//第一种情况。
else if(y==1582)a[2]=28;;//第二种情况。
else a[2]=(y%4==0&&y%100!=0||y%400==0?29:28);;//第三种情况。
if(y==1582&&m>=10&&d>=15)d-=10;//如果正好在1582年的10月15号及以后,减去 10。
while(m--)d+=a[m];//完整走完的月的总天数。
while(y--&&y){//完整走完的年的总天数
if(y<1582)d+=(y%4==0?366:365);//第一种情况。
else if(y==1582)d+=355;//第二种情况。
else d+=(y%4==0&&y%100!=0||y%400==0?366:365);//第三种情况。
}
cout<<d-1;//因为求的是与 1 年 1 月 1 日之间的天数,d 为天数,所以输出 d-1 。
}
代码可能有点漏洞,如有发现请在评论区指出或私聊我,会及时改正。
毕竟我不想被撤下题解。