NOIP2016普及组第二题——回文日期

题目描述

牛牛习惯用8位数字表示一个日期,其中,前4位代表年份,接下来2位代表月 份,最后2位代表日期。显然:一个日期只有一种表示方法,而两个不同的日期的表 示方法不会相同。

牛牛认为,一个日期是回文的,当且仅当表示这个日期的8位数字是回文的。现 在,牛牛想知道:在他指定的两个日期之间包含这两个日期本身),有多少个真实存 在的日期是回文的。

一个8位数字是回文的,当且仅当对于所有的i ( 1 <=i<= 8 )从左向右数的第i个 数字和第9-i个数字(即从右向左数的第i个数字)是相同的。

例如:

•对于2016年11月19日,用8位数字20161119表示,它不是回文的。

•对于2010年1月2日,用8位数字20100102表示,它是回文的。

•对于2010年10月2日,用8位数字20101002表示,它不是回文的。

每一年中都有12个月份:

其中,1、3、5、7、8、10、12月每个月有31天;4、6、9、11月每个月有30天;而对于2月,闰年时有29天,平年时有28天。

一个年份是闰年当且仅当它满足下列两种情况其中的一种:

1.这个年份是4的整数倍,但不是100的整数倍;

2.这个年份是400的整数倍。

例如:

•以下几个年份都是闰年:2000、2012、2016。

•以下几个年份是平年:1900、2011、2014。

输入输出格式

输入格式:
输入包括两行,每行包括一个8位数字。

第一行表示牛牛指定的起始日期。

第二行表示牛牛指定的终止日期。

保证date_i和都是真实存在的日期,且年份部分一定为4位数字,且首位数字不为0。

保证date1 —定不晚于date2。

输出格式:
输出一行,包含一个整数,表示在date1和date2之间,有多少个日期是回文的。

输入输出样例

输入样例#1:
20110101
20111231
输出样例#1:
1
输入样例#2:
20000101
20101231
输出样例#2:
2
说明

【样例说明】

对于样例1,符合条件的日期是20111102。

对于样例2,符合条件的日期是20011002和20100102。

【子任务】

对于60%的数据,满足date1 = date2。


这题我是用暴力直接搜,所以只对了六个点,拿了60分,还有四个点超时。

此题我的思路是直接一个 for 过去,再判断是否符合回文素数的要求。


代码如下:

var x,y,j,i,o,ans:longint;
    s:string;

function pd:boolean;
var  year,day,month:longint;
     x:string;
begin
  pd:=true;
  x:=copy(s,1,4);val(x,year);
  x:=copy(s,5,2);val(x,month);
  x:=copy(s,7,2);val(x,day);
  case month of
    1,3,5,7,8,10,12:if (day>31)or(day<0) then begin pd:=false; exit; end;
    4,6,9,11:if (day>30)or(day<0) then begin pd:=false; exit; end;
    2:if (year mod 400=0)or(year mod 4=0)and(year mod 100<>0) then if day>29 then begin pd:=false; exit; end
      else if day>28 then begin pd:=false; exit; end;
  end;
end;

begin
  assign(input,'date.in');
  assign(output,'date.out');
  reset(input);
  rewrite(output);
  read(x);
  read(y);
  for i:=x to y do
    begin
      str(i,s);
      if (copy(s,5,2)>'12')or(copy(s,5,1)='0')and(copy(s,6,1)='0')or(copy(s,7,2)>'31')or(copy(s,7,1)='0')and(copy(s,8,1)='0')or(copy(s,1,1)='0') then continue;
      o:=0;
      for j:=1 to length(s)div 2 do if s[j]<>s[length(s)-j+1] then begin o:=1; break; end;
      if o=0 then if pd=true then inc(ans);
      end;
  write(ans);
  close(input);
  close(output);
end.


修改后的算法:

枚举年分,年份中再枚举月份,再枚举日期,就可以避免没必要的循环。


代码如下:

const
  a:array[1..12]of longint=(31,28,31,30,31,30,31,31,30,31,30,31);
var
  s1,s2,s,m,d,i,j,k,ys,ye,ms,me,ds,de:longint;
begin
  readln(s1);
  readln(s2);
  ys:=s1 div 10000;
  ye:=s2 div 10000;
  ms:=(s1 mod 10000)div 100;
  me:=(s2 mod 10000)div 100;
  ds:=s1 mod 100;
  de:=s2 mod 100;
  for i:=ys to ye do
   begin
     a[2]:=28;
     if (i mod 4=0)and(i mod 100<>0)or(i mod 100=0)and(i mod 400=0) then
      a[2]:=29;
     for j:=1 to 12 do
      if (i=ys)and(j>=ms)or(i=ye)and(j<=me)or(1=1) then
       begin
         if j<10 then m:=j*10
          else m:=(j mod 10*10)+(j div 10);
         for k:=1 to a[j] do
          if (i=ys)and(j=ms)and(k>=ds)or(i=ye)and(j=me)and(k<=de)or(1=1) then
           begin
             if k<10 then d:=k*10
              else d:=(k mod 10*10)+(k div 10);
             if i=d*100+m then begin inc(s);break; end;
           end;
         if i=d*100+m then break;
       end;
   end;
  writeln(s);
  close(input);
  close(output);
end.
原文地址:https://www.cnblogs.com/Comfortable/p/8412479.html