首页 > 代码库 > SzNOI之d100题解题报名,日历问题

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

 

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