• 一道名题-(csp 儒略日)的心得与技巧


    引:

    如果你见到一个oi对着 47131582 146097 2299160 颠颠地笑,不用怀疑,他是在做那道名题--《csp-s2020 T1 儒略日》

    这道题,我做了三年,平均每年做一次,我来讲讲我的心得。

    读题

    题面很长,细节很多,我们需要耐心细心的读,此时多花一点时间是划得来的。

    我们得出大致关系如下

    {(){

    我们对公历都有一定的了解吧,比如 平年十二个月的天数, 比如小学教的 “一三五七八十腊”,四年一闰百年不闰四百年又闰,这些宝贵的经验将成为我们解题的关键说的呢。

    格里高利相较于公历其实更为简单,因为太简单不准所以才改的嘛 ,就是闰年的计算规则不同,是每四年一闰。

    解题

    首先,这是一道人尽皆知的模拟题。模拟的概念太笼统了,实现起来也八仙过海,我来讲讲我觉得最适合入手这道关于日期的大模拟。

    解题的方向

    我们要想着化繁为简,一个劲的分类讨论不见得总是好事(我第一次就这么G的)。

    多想想在 coding , 写代码的时间总是小于调 bug 的时间的。

    我的思路

    我们发现,将日期分为儒略历和公历是比较好的,将公元前的日期归化到儒略历的一部分,不用特殊处理,具体来讲,将公元前的日期年份 y >  y+1 比如BC 4713 变为 -4712 ,这阳处理闰年也方便。

    我们来算一下儒略历一共多少天

    首先公元前天数 365 * 4713 + 4713 / 4

    公元后的天数1581 * 365 + 1581 / 4 + 277 1582(不含)年以前的和1582年的277天。

    总共 2299160 天。

    对于较简单的儒略历,我们可以直接算

    int y = -4712, m = 1, d = 1;
        if (x <= Ru) {
            y += x / (_1 * 4 + 1) * 4;
            x %= (_1 * 4 + 1);
            while(x >= (_1 + (y % 4 == 0))) x -= (_1 + (y % 4 == 0)), y++;
            while(x >= (M[m] + (m == 2 && y % 4 == 0))) x -= (M[m] + (m == 2 && y % 4 == 0)), m++;
            d += x;
            if (y < 1) {
                cout << d << ' ' << m << ' ' << 1 - y << ' ' << "BC" << endl;
            } else {
                cout << d << ' ' << m <<' ' << y << endl;
            }
        }
    

    代码中(M[m] + (m == 2 && y % 4 ==0) 是处理闰年的二月日期(28->29)

    注意的是, 1 1 4713 BC 是第0天

    对于周期的存储,我们可以这样//公历下

    int _1 = 365, _4 = 4 * _1 + 1, _100 = 25 * _4 - 1, _400 = _100 * 4 + 1; //100,400是公历下的
    int M[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    

    对于公历, 我们考虑将1582 10 15 到 1982 10 14日这400年打一个小表,这样极大简化了我们的计算量

    else {
    		x -= Ru;
    		y = 0;
    		y += x / _400 * 400; x %= _400;
    		cout << a[x].d << ' ' << a[x].m << ' ' << y + a[x].y << endl;  
    	}
    

    其中a是打出来的表,a[x]是四百年中的第几天,10月15 日算第一天。

    那么,怎么打出这个表?

    答:用手打 可以用结构体。

    struct dt{
    	int y, m, d;
    	dt(){}
    	dt(int _y, int _m, int _d) {
    		y = _y, m = _m, d = _d;
    	}
    }a[maxn], be = {1582, 10, 15};
    

    然后四百年迭代一遍

     dt v = be;
      for (int i = 1; i <= _400; i++) {
      	a[i] = v;
      	nxt(v);
      }
    

    我们只需处理简单的一天的日期跳转

    void nxt(dt &x) {
    	x.d++;
    	if (x.d > (M[x.m] + ck(x))) {
    		x.d -= (M[x.m] + ck(x));
    		x.m++;
    	}
    	if (x.m > 12) {
    		x.m = 1;
    		x.y++;
    	}
    }
    

    ck 是处理闰年二月

    bool ck(dt x) {
    	if (x.y % 4 == 0 && x.y % 100 != 0 || x.y % 400 == 0) {
    		return x.m == 2;
    	} else return 0;
    }
    

    于是,我们便做完了这道大模拟。

    完结撒花!

    没有完!还有您对作者文章的肯定/否定没有留下,可以点赞或留言,作者都会看到!

    Our stories are still going on. 

  • 相关阅读:
    字符串相加
    【c++提高1】数据结构之哈希表
    hive通过正则过滤其他字段
    苹果系统_安装matplotlib_&_pygame,以pycharm导入模块
    若依注解学习(一)@Log
    使用qt5.6.3的注意事项:
    巾帼调查队开展实务调查技能,促全职妈妈联增收
    关于多线程的一切:原子操作
    缓冲区的奥秘:解析数据交错的魔法
    pandas或者matplotlib的饼图pie
  • 原文地址:https://www.cnblogs.com/Cranew/p/17300207.html