一.公式
基姆拉尔森计算公式 某大佬的推导
二.题型
①给定年月日是出这是今年的第几天;
//计算是这一年的第几天
int getDays(int y,int m,int d)
{
int sum = 0;
if(isLeapYear(y)) //闰年2月有29天
{
a[2]++;
}
for(int i = 1; i < m; i++)
{
sum += a[i];
}
sum += d;
return sum;
}
②给定年月日算星期几;
//利用基姆拉尔森年月日计算星期
int getWeek(int y,int m,int d)
{
if(m==1 || m==2)
{
m += 12;
y--;
}
//return (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%7; //周日返回0
return (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7+1; //周日返回7
}
③计算从某年某月某日开始的第n天(如 高斯日记)
#include <bits/stdc++.h>
using namespace std;
int a[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool isLeapYear(int y) //判断闰年
{
return (y%4==0 && y%100!=0)||(y%400==0);
}
string getData(int y,int m,int d,int n) //计算从y-m-d开始的第n天
{
while(--n)
{
d++;
if(m==12 && d==32) //过年啦~
{
y++;
m = 1;
d = 1;
continue;
}
if((m==1 || m==3 || m==5 || m==7 || m==8 || m==10) && d==32) //大月进入下一个月
{
m++;
d = 1;
continue;
}
if((m==4 || m==6 || m==9 || m==11) && d==31) //小月进入下一个月
{
m++;
d = 1;
continue;
}
if(m==2 && isLeapYear(y) && d==30) //闰年2月进入下一月
{
m++;
d = 1;
continue;
}
if(m==2 && !isLeapYear(y) && d==29) //平年2月进入下一月
{
m++;
d = 1;
continue;
}
}
stringstream ss;
ss << y << "-" << m <<"-" << d;
string ans;
ss >> ans;
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int y,m,d;
cin >> y >> m >> d;
//例如高斯日记中高斯获得博士学位的日子
cout << getData(1777,4,30,8113) << endl;
return 0;
}
三.例题
1.蓝桥杯 算法提高 日期计算
问题描述
已知2011年11月11日是星期五,问YYYY年MM月DD日是星期几?注意考虑闰年的情况。尤其是逢百年不闰,逢400年闰的情况。
输入格式
输入只有一行
YYYY MM DD
输出格式
输出只有一行
W
数据规模和约定
1599 <= YYYY <= 2999
1 <= MM <= 12
1 <= DD <= 31,且确保测试样例中YYYY年MM月DD日是一个合理日期
1 <= W <= 7,分别代表周一到周日
样例输入
2011 11 11
样例输出
5
#include <bits/stdc++.h>
using namespace std;
int a[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool isLeapYear(int y) //判断闰年
{
return (y%4==0 && y%100!=0)||(y%400==0);
}
int getweek(int yy,int mm,int dd)
{
if(mm<=2){
mm+= 12;
yy--;
}
return (dd+2*mm+3*(mm+1)/5+yy+yy/4-yy/100+yy/400)%7+1;
}
int main()
{
int yy ,mm,dd;
cin >> yy>>mm>>dd;
cout << getweek(yy,mm,dd);
}
2.计蒜客——节假日
问题描述
日历有阳历(公历)和阴历(农历)之分。每年都有法定节假日,这些分成三类——双休、阳历节假日、阴历节假日。
1.双休
1)周六和周日2天
2.阳历节假日
1)元旦:阳历每年1月1日,放假1天
2)劳动节:阳历每年5月1日,放假1天
3)国庆节:阳历每年10月1日,放假3天
4)圣诞节:阳历每年 12 月 25 日,放假1天
3.阴历节假日
1)春节:阴历每年1月1日,放假3天
2)清明节:阳历每年4月4-6日之间的某天,放假1天
3)端午节:阴历每年 5 月 5 日,放假1天
4)中秋节:阴历每年 8 月 15 日, 放假1天
当节假日和双休重合时,双休不延后也不提前,保证节假日之间不会重合。现在给你某年的所有阴历节假日的阳历日期,以及当年的1月1日是星期几,请你计算出这一年(阳历1月1日到12月31日)放了多少天假(包括双休、阳历节假日和阴历节假日)。
输入格式
第一行输入年份y(1900<y≤2050)。
接下来4行,每行输入两个整数m,d依次表示春节、清明节、端午节和中秋节的阳历日期。
最后一行一个整数表示当年1月1号是星期几(一周内的第几天,每周从星期一开始计数,即星期一为第一天)。
输出格式
输出一个整数,表示当年放假的天数。
样例输入
2017
1 28
4 4
5 30
10 4
7
样例输出
113
代码如下:
#include <bits/stdc++.h>
using namespace std;
int mm[10] = {1,5,10,10,10,12}; //阳历假期的月
int dd[10] = {1,1,1,2,3,25}; //阳历假期的日
int a[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
void nextday(int &y,int &m,int &d)
{
d++;
if(d==a[m]+1){
d=1;
m++;
}
}
bool isLeapYear(int y) //判断闰年
{
return (y%4==0 && y%100!=0)||(y%400==0);
}
int main()
{
int y,w,m,d,sf,ans;
scanf("%d",&y);
for(int i=6;i<=9;i++){
scanf("%d%d",&mm[i],&dd[i]);
}
scanf("%d",&w);
if(isLeapYear(y)){
a[2]++;
}
m=1;
d=1;
sf=0;
ans=0;
while(m<13){
if(m==mm[6]&&d==dd[6]){
ans++;
sf=2;
}else if(sf){
ans++;
sf--;
}else if(w==6||w==7){ //weekend
ans++;
}else{
for(int i=0;i<10;i++){ //肆无忌惮找数组
if(m==mm[i]&&d==dd[i]){
ans++;
break;
}
}
}
nextday(y,m,d);
w++;
if(w==8){
w=1;
}
}
printf("%d\n",ans);
return 0;
}