• SzNOI之d100题解题报名,日历问题


    SzNOI之d100题解题报名,日历问题

    d100: 神仙?妖怪?谢谢!

    这题的题目有点古怪。解题过程,且慢慢道来。

    搞懂这题,算日历,周几等问题,基本都搞清了。

    一、几年有几天

    二、到今天有几天

    三、打印日历


    一、几年有几天

    从公元一年,到公元n年,共有几天?

    这问题似乎相当简单,因为一年有365嘛。比如公元一年,到公元二年,这样算:

    var
      y,day:longint;
    begin
      y:=2; // 10
      day:=y*365;
      writeln(day);
    end.

    算下来,似乎一点错误也木有。

    那到公元十年呢?是不是把2改成10就可以了?

    不可以,因为闰年有366天。要这样计算:

    var
      i,y,day,d:longint;
      
    function leapy(y:longint):boolean;
    begin
      if(y mod 400=0) or (y mod 4=0) and (y mod 100<>0) then
        exit(true)
      else exit(false);
    end;
      
    begin
      y:=10; //2013
      d:=0;
      for i:=1 to y do
        if(leapy(i)) then inc(d);
      day:=y*365+d;
      writeln(day);
    end.

    是的,要把闰年多出来的一天,也加进去。

    应该是3652天,而不是3650天。

    分析一下,很容易明白,因为公元四年,与公元八年,是闰年。

    把10,改成2013试试?

    这样计算天数,并不是最快的。看程序:

    var
      i,y,day,d,e:longint;
      
    function leapy(y:longint):boolean;
    begin
      if(y mod 400=0) or (y mod 4=0) and (y mod 100<>0) then
        exit(true)
      else exit(false);
    end;
      
    begin
      y:=2013;
      d:=0;
      for i:=1 to y do
        if(leapy(i)) then inc(d);
      day:=y*365+d;
      writeln(d);
      writeln(day);
      e:=(y div 4)-(y div 100)+(y div 400);
      writeln(e);
    end.

    两种算法,得出的结论是一样的,都是488。

    当然是第二种算法快得多,不用循环,直接算出来了。

    我们可以粗略理解一下,整除4,闰年多了点。那么减去一些(整除100的结果),那又太少了一些,那么再加上一点。。

    好了,以下的算法很快就能计算出,从公元一年到y年,共有几个闰年,共有几天:

    var
      y,day,d:longint;
    begin
      readln(y); // y:=2013;
      d:=(y div 4)-(y div 100)+(y div 400);
      day:=y*365+d;
      writeln(d);
      writeln(day);
    end.

    二、到今天有几天

    从公元一年的一月一日开始,到今天,共有几天呢?

    要分三步走:

    公元一年,到去年,共有几天。

    今年一月,到这个月的前一个月,共有几天。

    这个月的一号,到今天,共有几天。

    const
      a:array[0..12] of longint = 
      (0,31,28,31,30,31,30,31,31,30,31,30,31);
    var
      i,t,y,day,d,m,dd:longint;
      
    function leapy(y:longint):boolean;
    begin
      if(y mod 400=0) or (y mod 4=0) and (y mod 100<>0) then
        exit(true)
      else exit(false);
    end;  
     
    begin
      y:=2013; //2014年的前一年,是2013年
      m:=11;   //当月是11月
      dd:=1;   //1号
      d:=(y div 4)-(y div 100)+(y div 400);
      day:=y*365+d;
      t:=0;
      for i:=1 to m-1 do inc(t,a[i]); //1月到前一个月的天数
      if( (m>2) and leapy(y) ) then inc(t); //闰年多加一天
      inc(day,t);  //到前个月底有几天
      inc(day,dd); //到今天有几天
      writeln(day);
    end.

     那今天是周几?

    公元一年的元旦的前一天,是周日。这个非常好记,因为传说上帝创世纪之后,是在周日休息的。

    到了公元一年的第一天,出来干活了,是周一。

    公元一年的元旦的前一天,我们暂时称之为公元前末日。

    从公元前末日,到今天,相差几天,我们前面已经计算出来了。

    而公元前末日,是周日,那今天是周几,就非常好算了,看程序:

    const
      a:array[0..12] of longint = 
      (0,31,28,31,30,31,30,31,31,30,31,30,31);
    var
      i,t,y,day,d,m,dd:longint;
      
    function leapy(y:longint):boolean;
    begin
      if(y mod 400=0) or (y mod 4=0) and (y mod 100<>0) then
        exit(true)
      else exit(false);
    end;  
     
    begin
      y:=2013; //去年
      m:=11;
      dd:=1;
      d:=(y div 4)-(y div 100)+(y div 400);
      day:=y*365+d;
      t:=0;
      for i:=1 to m-1 do inc(t,a[i]);
      if( (m>2) and leapy(y+1) ) then inc(t); //闰年多加一天
      inc(day,t); //到前个月底有几天
      inc(day,dd); //到今天有几天
      writeln(day);
      case (day mod 7) of
        0 : writeln('Sunday'); //公元前末日是周日
        1 : writeln('Monday');
        2 : writeln('Tuesday');
        3 : writeln('Wednesday');
        4 : writeln('Thursday');
        5 : writeln('Friday');
        6 : writeln('Saturday');
      end;  
    end.

     是周六,对吧?

    那么稍微修改一下程序,对于任意年月日是周几,都可以准确、精确地算出来了:

    const
      a:array[0..12] of longint = 
      (0,31,28,31,30,31,30,31,31,30,31,30,31);
    var
      i,t,y,day,d,m,dd:longint;
      
    function leapy(y:longint):boolean;
    begin
      if(y mod 400=0) or (y mod 4=0) and (y mod 100<>0) then
        exit(true)
      else exit(false);
    end;  
     
    begin
      readln(y,m,dd);
      y:=y-1; //年份算到去年
      d:=(y div 4)-(y div 100)+(y div 400);
      day:=y*365+d;
      t:=0;
      for i:=1 to m-1 do inc(t,a[i]);
      if( (m>2) and leapy(y+1) ) then inc(t); //今年是y+1
      inc(day,t);
      inc(day,dd);
      case (day mod 7) of
        0 : writeln('Sunday');
        1 : writeln('Monday');
        2 : writeln('Tuesday');
        3 : writeln('Wednesday');
        4 : writeln('Thursday');
        5 : writeln('Friday');
        6 : writeln('Saturday');
      end;  
    end.
    View Code

    三、打印日历

    有了前面的铺垫,解题报告正式开始。

    似乎、好像、仿佛,已经没有什么好说的了,直接看程序:

    const
      a:array[0..12] of longint = 
      (0,31,28,31,30,31,30,31,31,30,31,30,31);
      w:array[0..6] of string =
      ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
    var
      i,t,y,day,d,m,dd:longint;
      
    function leapy(y:longint):boolean;
    begin
      if(y mod 400=0) or (y mod 4=0) and (y mod 100<>0) then
        exit(true)
      else exit(false);
    end;  
     
    begin
      readln(y,m);
      y:=y-1; //年份算到去年
      dd:=1;
      d:=(y div 4)-(y div 100)+(y div 400);
      day:=y*365+d;
      t:=0;
      for i:=1 to m-1 do inc(t,a[i]);
      if( (m>2) and leapy(y+1) ) then inc(t); //今年是y+1
      inc(day,t);
      inc(day,dd);
      //
      d:=day mod 7; //得出1号是周几
      for i:=0 to 6 do //输出第一行
        write(w[i]:4);
      writeln;
      t:=0;
      for i:=1 to d do begin //输出第二行前面的的空格。d如是0,不进入循环
        write(' ':4);
        inc(t);
      end;
      dd:=a[m]; //当月有几天
      if( (m=2) and leapy(y+1)) then inc(dd); //如是闰年2月,要加一天
      for i:=1 to dd do begin
        write(i:4);
        inc(t);
        if(t mod 7=0) then writeln; //t为7的倍数,换行
      end;
      writeln;
    end.

    嗯,好像不太复杂吧。输入年、月,就能打印出日历,很COOL的样子 ^_^

    到此结束,有问题请留言。

    TOP

  • 相关阅读:
    python linecache模块 快速读取模块某行
    51单片机扩展protues仿真
    python 字符串过滤技巧 搜索目录
    51单片机(STC89C52RC)光电耦合控制继电器实验
    python 获取当前当前目录 脚本目录 被执行脚本目录
    51单片机(STC89C52RC)EEPROM操作实验
    Python 拷贝对象(深拷贝deepcopy与浅拷贝copy)
    Python __getattr__与__setattr__使用方法
    51单片机(STC89C52RC)看门狗设置
    jquery的Dtree树插件简单使用
  • 原文地址:https://www.cnblogs.com/xin-le/p/4067876.html
Copyright © 2020-2023  润新知