今天开始打算做一下历年的noip和csp的真题,感受一下到底考了哪些内容。
先从csp-s 2020开始吧,首先是这道T1,昨天调了一天。。。

csp的好像牛客网没有找到,我在洛谷做的。
题目链接:
https://www.luogu.com.cn/problem/P7075

思路:
看题目就知道模拟肯定可以。
我在这里分了几种情况:
① 公元前,从-4713到-1年。一共4713年,其中根据题目意思,-1,-5,-9...-4713是闰年。
那么我们一共有1178个闰年,3535个平年,一共有t1=1721423天。
所以第一段就是当输入的天数T<=1721423,我们可以直接统一输出到公元前的情况。这里显然是4年一周期,那么我们可以得到一个周期为366+365*3=1461天,那我们先4年4年的算,然后直接模拟月和日的情况。
②公元后,我在这里处理到从1年1月1日到1582年10月4日,这里先计算1-1581年的天数,395个闰年+1186个平年,再加上1582年的277天,一共有t2=577460天。
所以第二段就是当输入的天数T <= t1+t2 = 2299160天时候,我们输出公元1年到1582年的情况,这里也是4年一周期,先对T减去1721424以后,方法同第一种情况。
③从1582年10月15日以后就是格里高历了,那么在这里我先处理到了1582-10-15到1599-12-31的情况,这里一共是6287天,那么当T<=2305812时,这一部分我们直接模拟。
④最后模拟1600-1-1以后的情况,这里我们要注意闰年的判断方法改变了,不能再是4年一周期了。不过我们可以把周期扩大到400年,每400年中有97个闰年和303个平年,那么一共是146097天,每400年一个周期。
所以我们先计算出有多少个400年的周期,然后再模拟就好了。

说起来挺容易,其实中间模拟的时候有一些地方细节挺多。
中间有一个solve没有开longlong,T了好多发。

附上具丑的代码:

#include<bits/stdc++.h>
using namespace std;
int y[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int year,month,day;
inline long long read()
{
    long long x=0,y=1;char c=getchar();//y代表正负(1.-1),最后乘上x就可以了。
    while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}//如果c是负号就把y赋为-1
    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*y;//乘起来输出
}
void solve(long long d){
    long long t=d/1461;   //4年一周期 
    d-=t*1461;
    year=4713-t*4;
    month=1;day=1;
    int flag=0;
    while(d){ 
        for(int i=1;i<=12;i++){
            int tmp=y[i];
            if(i==2&&(year-1)%4==0)tmp++;
            if(d>tmp)d-=tmp;
            else {
                month=i;
                day=d+1;
                if(day>tmp){
                    month++,day-=tmp;
                    if(month>12)month=1,year--;
                }
                d=0;
                return;
            }
        }
        year--;
    }
}
void solve2(long long d){
    long long t=d/1461; 
    d-=t*1461;
    year=t*4+1;
    month=1;
    day=1;
    int flag=0;
    while(d){
        int tmp=365;
         if(year%4==0)tmp++;
         if(d>tmp){
             year++;
             d-=tmp;
             continue;
         } 
        for(int i=1;i<=12;i++){
            int tmp=y[i];
            if(i==2&&year%4==0)tmp++;
            if(d>tmp)d-=tmp;
            else {
                month=i;
                day=d+1;
                if(day>tmp){
                    month++,day-=tmp;
                    if(month>12)month=1,year++;
                }
                d=0;
                return ;
            }
        }
        year++;
    }
}
void solve3(long long d){  
    year=1582;
    month=10;
    day=15;
    if(d<=16){
        day+=d;
        return;
    }
    d-=17;
    int flag=0;
    while(d){
        for(int i=(flag==0)?11:1;i<=12;i++){
            flag=1;
            int tmp=y[i];
            if(i==2&&year%4==0)tmp++;
            if(d>tmp)d-=tmp;
            else {
                month=i;
                day=d+1;
                if(day>tmp){
                    month++,day-=tmp;
                    if(month>12)month=1,year++;
                }
                d=0;
                return ;
            }
        }
        year++;
    }
}
bool judge(int x){
    if(x%400==0)return true;
    else if(x%4==0&&x%100!=0)return true;
    return false;
}
void solve4(long long d){
    long long t=d/146097;
    year=1600+t*400;
    month=1;day=1;
    d-=t*146097;
     while(d){
         int tmp=365;
         if(judge(year))tmp++;
         if(d>tmp){
             year++;
             d-=tmp;
             continue;
         } 
        for(int i=1;i<=12;i++){
            int tmp=y[i];
            if(i==2&&judge(year))tmp++;
            if(d>tmp)d-=tmp;
            else {
                month=i;
                day=d+1;
                if(day>tmp){
                    month++,day-=tmp;
                    if(month>12)month=1,year++;
                }
                d=0;
                return ;
            }
        }
        year++;
    }
}
int main()
{
//    freopen("f2.in","r",stdin);
//    freopen("f.out","w",stdout);
    int Q;
    cin>>Q;
    long long d;
    while(Q--){
        d=read();
        if(d<=1721423){  //bc
            solve(d); 
            printf("%d %d %d BC\n",day,month,year);
        }
        else if(d<=2299160){        //  before 1582-10-4
            d-=1721424;
            solve2(d);
            printf("%d %d %d\n",day,month,year);
        }
        else if(d<=2305447){    //1582-10-15 到1599-12-31 
            d-=2299161;
            solve3(d);
            printf("%d %d %d\n",day,month,year);

        }
        else{    //1600-1-1开始400年一周期 
            d-=2305448;
            solve4(d);
            printf("%d %d %d\n",day,month,year);
        }
    }
    return 0;
}