今夕何夕
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1668 Accepted Submission(s): 594
小度独自凭栏,望着一轮圆月,发出了“今夕何夕,见此良人”的寂寞感慨。
为了排遣郁结,它决定思考一个数学问题:接下来最近的哪一年里的同一个日子,和今天的星期数一样?比如今天是8月6日,星期日。下一个也是星期日的8月6日发生在2023年。
小贴士:在公历中,能被4整除但不能被100整除,或能被400整除的年份即为闰年。
每组数据包含一个日期,格式为YYYY-MM-DD。
1 ≤ T ≤ 10000
YYYY ≥ 2017
日期一定是个合法的日期
3 2017-08-06 2017-08-07 2018-01-01
2023 2023 2024
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=6112
题意简单,但是日期类题目计算有点麻烦。。。。
1.直接模拟。
题目中说‘今天’是2017年8月6日,星期日,我们要寻找下一个8月6日也是星期日的年份。
这里要分三种情况进行讨论。
1.1 若开始日期在在3月以后(包含3月,无论今年是平年还是闰年),则到下一年今天则会经过365天,星期数会向后推一天(365%7=1)
1.2 若开始日期在2月29日,则到下一个2月29日至少要过4年。
1.3 如开始日期在2月29日之前:
1.3.1 若今年为闰年,则到明年今日要经过366天,否则为365天。
AC代码1.
模拟:
/**
* 行有余力,则来刷题!
* 博客链接:http://blog.csdn.net/hurmishine
* 个人博客网站:http://wuyunfeng.cn/
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e1+5;
int a[maxn];
int getDay(int y)//年份天数
{
/**
364/7=52
*/
if(y%400==0||y%100!=0&&y%4==0)
return 2;
return 1;
}
int main()
{
//freopen("C:\\Users\\hncu_acm\\Desktop\\data.txt","r",stdin);
int T;
cin>>T;
while(T--)
{
int y,m,d;
scanf("%d-%d-%d",&y,&m,&d);
int sum=0;
if(m>2)
{
do
{
y++;
sum+=getDay(y);
sum%=7;
}
while(sum);
}
else
{
if(m==2&&d==29)
{
do
{
y++;
sum+=getDay(y);
sum%=7;
if(sum==0&&getDay(y)==2)
break;
}
while(true);
}
else
{
do
{
sum+=getDay(y);
y++;
sum%=7;
}
while(sum);
}
}
cout<<y<<endl;
}
return 0;
}
AC代码2:
基姆拉尔森计算公式:
W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7
在公式中d表示日期中的日数,m表示月份数,y表示年数。注意:在公式中有个与其他公式不同的地方:
把一月和二月看成是上一年的十三月和十四月,例:如果是2004-1-10则换算成:2003-13-10来代入公式计算。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>
#include <math.h>
#include <queue>
#define LL long long
using namespace std;
int year,month,day;
bool isLeap(int x)
{
if((x%4==0&&x%100!=0)||x%400==0)
return true;
return false;
}
int cal(int y,int m,int d)
{
if(m<3)
{
m+=12;
--y;
}
int W=(d+1+2*m+3*(m+1)/5+y+(y>>2)-y/100+y/400)%7;
return W==0?7:W;
}
bool judge(int x)
{
//起始年是闰年,但是今年不是
if(isLeap(year)&&!isLeap(x)&&(month==2&&day==29))
{
return true;
}
return false;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d-%d-%d",&year,&month,&day);
int pos=cal(year,month,day);
int kk;
for(int i=year+1;; ++i)
{
kk=cal(i,month,day);
if(judge(i)) continue;
if(kk==pos)
{
printf("%d\n",i);
break;
}
}
}
return 0;
}
AC代码3,
蔡勒公式
以1582年10月4日为例:
1582年10月4日后:w = (d + 1+ 2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7;
1582年10月4日前:w = (d+1+2*m+3*(m+1)/5+y+y/4+5) % 7;
w:星期; w对7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六
c:世纪(年份前两位数)
y:年(后两位数)
m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算)
d:日
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <iostream>
using namespace std;
int is_run(int year)
{
if(year%400==0||(year%4==0&&year%100!=0))
return 1;
return 0;
}
int Zeller(int year,int month,int day)///蔡勒公式算星期
{
if (month==1||month==2)
{
year--;
month+=12;
}
int c=year/100;
int y=year-c*100;
int week=(c/4)-2*c+(y+y/4)+(13*(month+1)/5)+day-1;
while(week<0){week+=7;}
week%=7;
return week;
}
int main()
{
int year,month,day,T;
scanf("%d",&T);
while (T--)
{
scanf("%d-%d-%d",&year,&month,&day);
int week=Zeller(year,month,day);
int week2;
if (month==2&&day==29)///如果输入为闰年的2月29号
{
for (int i=year+4;i<=9999;i+=4)///每四年枚举
{
if (!is_run(i)) continue;///不是闰年就PASS
week2=Zeller(i,month,day);
if (week==week2)
{
printf("%d\n",i);
break;
}
}
}
else
{
for (int i=year+1;i<=9999;i++)
{
week2=Zeller(i,month,day);
if (week==week2)
{
printf("%d\n",i);
break;
}
}
}
}
return 0;
}
参考博客: http://blog.csdn.net/clx55555/article/details/77154461
http://blog.csdn.net/exchan/article/details/77127039
http://blog.csdn.net/qq_32792879/article/details/77140445
测试数据:
10
2017-08-06
2018-08-07
2019-08-06
2020-08-07
2021-08-06
2017-01-07
2018-01-01
2019-01-07
2020-01-01
2020-02-29
2023
2029
2024
2026
2027
2023
2024
2030
2025
2048