目前本菜鸡在CSP认证、蓝桥杯以及牛客网校招练习题上,刷到的有关日期的问题有四种。
第一种:输入年、月、日,计算该天是本年的第几天。(来源:牛客网
解题思路:
这种问题的求解比较简单。首先用一个数组来记录每个月的天数,其中默认二月的天数为28天,如果是闰年则让2月的天数加1。然后无脑累加1至m-1个月的天数再加上输入的日数就能得出输入的年月日是本年中的第几天。

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int a[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    int y,m,d; 
    cin >> y >> m >> d;
    int cnt = 0;   //本年的第几天  
    if((y%4==0&&y%100!=0) || y%400==0) { //闰年
        a[2]++;   //写这种题都是一次性程序直接加了,2月有29天
    }
    for(int i = 1; i < m; i++) {
        cnt += a[i];
    }
    cnt += d;
    cout << cnt << endl;
    return 0;
}

第二种:输入年和天数,计算出是本年的几月几日。(来源:CSP认证
解题思路:
这种问题和第一种问题很相似,只是输入输出相反 求解起来比较简单。用一个数组来存放每个月的最大天数,若输入的y是闰年则将2月份的天数加1。当日期大于当前月份总天数时 不断地将日期减去当前月份总天数并将月份+1,直到剩余的天数不大于当前月份总天数即可,最后输出月份和日期。

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int a[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    int y,d; 
    cin >> y >> d;
    int m = 1;  
    if((y%4==0&&y%100!=0)||y%400==0) { //闰年
        a[2]++;   //2月有29天
    }
    while(d > a[m]) { //日期大于当前月份总天数
        d -= a[m];
        m++;
    }
    cout << m << endl << d << endl;
    return 0;
}

第三种:给定年月日,输入天数,计算从某年某月某日开始,经历若干天后的年月日。(即高斯问题,来源:蓝桥杯
解题思路:
水题,注意考虑年份、月份的进位就行了。①当月份是12,日期是32时年份进位再把月日归1。②大月在日期是32时月份进位再把日期归1。③小月是31时月份进位再把日期归1。④闰年2月在日期为30时月份进位再把日期归1。⑤平年2月在日期为29时月份进位再把日期归1。

#include <bits/stdc++.h>
using namespace std;

bool isLeapYear(int y) {
    return (y%4==0 && y%100!=0) || (y%400 == 0);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int y = 1777,m = 4,d = 30;
    int n;
    cin >> 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;
        }
    }
    cout << y << "-" << m << "-" << d << endl;
    return 0;
}

第四种:给定年月日,计算星期几。
解题思路:根据年月日计算星期可以直接用基姆拉尔森计算公式进行求解。需要注意的是原始公式(d+2m+3(m+1)/5+y+y/4-y/100+y/400+1)%7中计算出的星期日为0,这里可以简单地变形一下用(d+2m+3(m+1)/5+y+y/4-y/100+y/400)%7+1直接求得星期日为7。

#include <bits/stdc++.h>
using namespace std;

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)%7+1;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int y,m,d;
    cin >> y >> m >> d;
    cout << getWeek(y,m,d) << endl;
    return 0;
}