NOIP2016第二题

题目:https://www.luogu.org/problem/show?pid=2010

周俊豪同学的分析及代码:

var
  ans,d1,d2,i,k,n,y,r:longint;
  a:array[1..8] of byte;
  p:boolean;
begin
  readln(d1,d2);
  r:=d1 mod 100;
  d1:=d1 div 100;
  y:=d1 mod 100;
  d1:=d1 div 100;//分离年月日
  n:=d1;
  while (n*10000+y*100+r)<=d2 do begin
    k:=n*10000+y*100+r;//当前的年月日(8位数)
    for i:=1 to 8 do begin
      a[i]:=k mod 10;
      k:=k div 10;
    end;//分离每个数字
    if (a[1]=a[8])and(a[2]=a[7])and(a[3]=a[6])and(a[4]=a[5]) then inc(ans);//判断回文

    if ((n mod 4=0)and(n mod 100<>0)) or (n mod 400=0) then p:=true
                                                       else p:=false;//判断是否为闰年
    inc(r);//加一天
    if (r=32) and ((y=1)or(y=3)or(y=5)or(y=7)or(y=8)or(y=10)or(y=12)) then begin
      r:=1;
      inc(y);
    end;//大月进位
    if (r=31) and ((y=4)or(y=6)or(y=9)or(y=11)) then begin
      r:=1;
      inc(y);
    end;//小月进位
    if (r=29) and (y=2) then begin//未加and(p=false),闰年错误
      r:=1;
      y:=3;
    end;//非闰年2月进位
    if (r=30) and (y=2) and p then begin
      r:=1;
      y:=3;
    end;//闰年2月进位
    if y=13 then begin
      inc(n);
      y:=1;
    end;//年进位
  end;
  writeln(ans);//输出
end.

韩天意同学的分析及代码:

var
  a1,b1,i,n,y,r,g,s1,s2,ans,z,f,i1:longint;
  a,b:string;
  j:array[1..8]of byte;
begin
  assign(input,'date.in');
  reset(input);
  assign(output,'date.out');
  rewrite(output);
  readln(a);//以字符串的形式读入2个日期
  readln(b);
  ans:=0;
  for i:= 1 to 8 do a1:=a1*10+(ord(a[i])-48);
  for i:= 1 to 8 do b1:=b1*10+(ord(b[i])-48);//把字符串转回数字
  for i:=a1 to b1 do begin
    i1:=i;//
    n:=i div 10000;//计算出年
    y:=(i mod 10000) div 100;//计算出月
    r:=i mod 100;//计算出日
    if (y>=1) and (y<=12) then begin//判断月份是否存在
      case y of//判断月份中应有多少日子
      1,3,5,7,8,10,12: g:=31;
      4,6,9,11:g:=30;
      2:if (n mod 400=0)or((n mod 100<>0) and(n mod 4=0))then g:=29
                                                         else g:=28;
      end;
      if (r>=1)and(r<=g)then begin//判断日期是否在范围内
        f:=100000000;
        for z:=1 to 8 do begin
          f:=f div 10;
          j[z]:=i1 div f;
          i1:=i1 mod  f;
        end;//把数字转换成数组,方便判断是否是回文
          s1:=1;s2:=8;
          while s1<s2 do begin
            if j[s1]=j[s2] then begin inc(s1);dec(s2);end
                           else break;
          end;
          if s1>s2 then ans:=ans+1;//判断回文
      end;
    end;
  end;
  writeln(ans);
  close(input);
  close(output);
end.

  这道题使用字符串完全是多余的。使用for语句来暴力搜索过慢导致了:虽然检查后答案都对,却有超时。只得到70分。要拿满分
  经查看他人题解,发现另有个简单的方法,代码如下:
var 
  a:array [1..12] of longint=(31,28,31,30,31,30,31,31,30,31,30,31);
  date1,date2,i,ans,r1,y1,r2,y2,m,d:longint;
function use(y:longint):boolean;
begin 
  d:=y div 100;
  m:=y mod 100;
  d:=(d mod 10)*10+d div 10;
  m:=(m mod 10)*10+m div 10;
  if ((m>=1)and(m<=12))and((d>=1)and(d<=a[m])) then begin ans:=ans+1;exit(true);end
                                               else exit(false);
end;
begin
  read(date1,date2);
  y1:=date1 mod 10000 div 100;r1:=date1 mod 100;y2:=date2 mod 10000 div 100;r2:=date2 mod 100;
  for i:=date1 div 10000 to date2 div 10000 do begin 
    if (i mod 4=0)and((i mod 100<>0)or(i mod 400=0)) then a[2]:=29 else a[2]:=28;
    if (use(i)) then begin 
      if ((i=date1 div 10000)and(m<y1))or((i=date1 div 10000)and(m=y1)and(d<r1)) then ans:=ans-1;
      if ((m>y2)and(i=date2 div 10000))or((m=y2)and(i=date2 div 10000)and(d>r2))then ans:=ans-1;
    end;
  end;
  write(ans);
end.

刘可盈的分析及代码:

var
  date1,date2,i,d,y,m,yy,dm,ans:longint;
begin
  assign(input,'date.in');reset(input);
  assign(output,'date.out');rewrite(output);
  readln(date1);
  readln(date2);
  ans:=0;
  for i:=date1 to date2 do begin     //  从date1循环到date2
    y:=i;                            //把年月日算出来
    d:=y mod 100;
    y:=y div 100;
    m:=y mod 100;
    y:=y div 100;
    case m of                                //把不正确的日期去掉
      1,3,5,7,8,10,12:if d>31 then continue;
      4,6,9,11:if d>30 then continue;
      2:if ((y mod 4=0) and (y mod 100<>0)) or (y mod 400=0) then
          if d>29 then continue
         else if d>28 then continue;
      else continue;
    end;
    yy:=0;
    while y>0 do begin                        //把年份倒过来
      yy:=yy*10+(y mod 10);
      y:=y div 10;
    end;
    dm:=m*100+d;                             //把月份和日期放在一起
    if dm=yy then ans:=ans+1;                //检查是否是回文
  end;
  writeln(ans);
  close(input);
  close(output);
end.

 

posted @ 2017-01-12 15:11  lsnoip  阅读(204)  评论(0)    收藏  举报