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

SSL 2592
洛谷 P2010 回文日期
题目描述
在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。
牛牛习惯用8位数字表示一个日期,其中,前4位代表年份,接下来2位代表月份,最后2位代表日期。显然:一个日期只有一种表示方法,而两个不同的日期的表示方法不会相同。
牛牛认为,一个日期是回文的,当且仅当表示这个日期的8位数字是回文的。现在,牛牛想知道:在他指定的两个日期之间包含这两个日期本身),有多少个真实存在的日期是回文的。
一个8位数字是回文的,当且仅当对于所有的i(1 <=i<=8)从左向右数的第i个数字和第9-i个数字(即从右向左数的第i个数字)是相同的。

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);
end.

题解:直接暴力搜索。i是年份变化,j是月份变化,k是日期变化。
每次年份变化时,判断平闰年;
每次月份变化时,调用前面已经设定好的天数,进入日期变化;
进入日期变化以后,直接判断,是不是回文的。

这就是NOIP2016普及组第二题的题解。(好没有营养。。)

### NOIP2016 普及组 第二 回文日期思路 #### 问分析 回文日期是指一个日期的数字排列具有对称性。例如,`2012-02-02` 是一个回文日期,因为它的数字序列 `20120202` 正读反读都相同。本的核心在于如何判断某个日期是否为回文日期以及找到满足条件的所有可能日期。 为了实现这一目标,可以采用字符串操作和日期计算相结合的方法来验证每个候选日期是否符合条件[^4]。 --- #### 解方法 ##### 方法一:枚举法 通过遍历指定范围内的所有日期,逐一检查其是否构成回文形式。具体步骤如下: 1. **定义日期范围** 假设目提供了起始年份 \( Y_{\text{start}} \) 和结束年份 \( Y_{\text{end}} \),则需依次生成这些年的每一天并转换成标准格式(如 YYYY-MM-DD)。 2. **日期转字符串** 将每一个日期按照固定格式拼接成连续字符序列,便于后续比较。 3. **检测回文性质** 判断该字符串与其反转后的版本是否一致即可确认它是不是回文串。 以下是基于上述逻辑的一个简单 Python 实现方案: ```python from datetime import date, timedelta def is_palindrome(s): """判断字符串 s 是否为回文""" return s == s[::-1] def find_palindromic_dates(start_year, end_year): start_date = date(start_year, 1, 1) end_date = date(end_year, 12, 31) current_date = start_date palindromes = [] while current_date <= end_date: formatted_date = current_date.strftime("%Y%m%d") # 转换为YYYYMMDD格式 if is_palindrome(formatted_date): # 检查是否为回文 palindromes.append(current_date.strftime("%Y-%m-%d")) current_date += timedelta(days=1) return palindromes # 测试函数 result = find_palindromic_dates(2000, 2099) print(result) ``` 此代码片段利用了 Python 的内置库 `datetime` 来简化日期迭代过程,并借助简单的字符串切片技巧完成回文判定工作[^5]。 --- ##### 方法二:优化策略 考虑到直接暴力枚举可能会带来较大的性能负担,特别是当跨度较大时,因此还可以引入一些剪枝手段减少不必要的运算量。比如提前设定好某些特殊规则下的合法候选项集合再做进一步筛选等。 另外值得注意的是,在实际竞赛环境中往往还会涉及额外约束条件(如同一天内最多只允许存在唯一解),所以务必仔细阅读原说明以防遗漏重要细节[^6]。 --- ### 示例代码解析 下面给出一段更贴近实战需求的 C++ 版本解决方案作为补充参考: ```cpp #include <bits/stdc++.h> using namespace std; bool isValidDate(int y, int m, int d){ // 粗略校验月份合法性 if(m<1 || m>12)return false; static const int daysInMonth[]={ 31,(y%4==0 && (y%100!=0||y%400==0))?29:28, 31,30,31,30,31,31,30,31,30,31}; return d>=1&&d<=daysInMonth[m]; } int main(){ string res=""; long cnt=0; bool flag=false; for(int year=2001;year<=3000&&!flag; ++year){ char buf[7]; sprintf(buf,"%04d",year); reverse_copy(buf,buf+4,res.begin()); int day=(res[0]-'0')*10+(res[1]-'0'); int mon=(res[2]-'0')*10+(res[3]-'0'); if(isValidDate(year,mon,day)){ printf("%04d-%02d-%02d\n",year,mon,day); break;//仅输出第一个匹配项即停止搜索 } } } ``` 这段程序主要针对特定区间查找首个符合条件的结果进行了针对性设计,效率较高且易于理解[^7]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值