NOIP 普及组 2016 回文日期

本文介绍了一种计算在指定日期范围内回文日期数量的方法。通过两种思路解析:一是寻找每年的回文日期,二是枚举月和日对应的回文年份。提供了详细的算法思路和AC代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

https://www.cnblogs.com/violet-acmer/p/9859003.html

 

题解:

 思路1:

  相关变量解释:

    year1,month1,day1 : date1对应的年、月、日

    year2,month2,day2 : date2对应的年、月、日

  这道题算是考思维+Code能力??

  易得,每一年最多有一个回文日期;

  例如 2000 的回文日期为 2000 0002

  for i : year1 to year2

    找到每个 i 的回文日期对应的月(month)、日(day),并进行两个判断

    (1):判断month,day是否合法。

    (2):判断当前日期是否在date1与date2之间

 思路2.

  枚举月和日对应的回文年份,看其回文组成的八位数是否在date1和date2内,什么意思呢?

  例如,对于01月23日,其对应的回文年份为3210,其回文组成的八位数为 32100123,在和输入的date1与date2比较,看是否在其中,如果在,Count++;

  不用特判某一年是否为闰年,为什么呢?

  某年是否为闰年只会影响 2 月的天数,2月最多有 29 天,其对应的回文年份为 9220,但9220是闰年。

  思路2来自集训队队员博客:https://blog.youkuaiyun.com/QLU_minoz/article/details/83450635

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define isSat(x) ((x) >= 1 &&(x) <= 12)//判断是否为合法的月份
 4 #define isRun(x) ((x%4 == 0 && x%100 != 0) || (x%400 == 0))//判断是否为闰年
 5 
 6 char data[2][8];
 7 int monthDay[2][13]={{0,31,28,31,30,31,30,31,31,30,31,30,31}, //0 : 平年
 8                      {0,31,29,31,30,31,30,31,31,30,31,30,31}};//1 : 闰年
 9 
10 int Transform(int a,int b,int d){//将字符串对应的年、月、日转化成数子
11     int num=0;
12     for(int i=a;i <= b;++i)
13         num=num*10+(data[d][i]-'0');
14     return num;
15 }
16 void Search(int year,char *s){
17     int index=0;
18     do
19     {
20         s[index++]=year%10+'0';
21         year /= 10;
22     }while(year != 0);
23 }
24 void Solve()
25 {
26     int year1=Transform(0,3,0),month1=Transform(4,5,0),day1=Transform(6,7,0);
27     int year2=Transform(0,3,1),month2=Transform(4,5,1),day2=Transform(6,7,1);
28     int res=0;
29     int pre=0;
30     for(int i=year1;i <= year2;++i)
31     {
32         char s[4];
33         Search(i,s);//找到将当前的年份的回文
34         int month=(s[0]-'0')*10+(s[1]-'0');//当前年份的回文对应的月
35         int day=(s[2]-'0')*10+(s[3]-'0');//
36         if(!isSat(month) || day > monthDay[isRun(i)][month])
37             continue;
38         if(year1 == year2)
39         {
40             if(month > month1 || (month == month1 && day >= day1))
41             {
42                 if(month < month2 || (month == month2 && day <= day2))
43                     res++;
44             }
45         }
46         else
47         {
48             if(i == year1)
49                 res += (month > month1 || (month == month1 && day >= day1) ? 1:0);
50             else if(i == year2)
51                 res += (month < month2 || (month == month2 && day <= day2) ? 1:0);
52             else//如果year1 != year2 ,且 i != year1 && i != year2 ,则当前合法的日期一定在date1和date2之间
53                 res++;
54         }
55     }
56     printf("%d\n",res);
57 }
58 int main()
59 {
60     scanf("%s%s",data[0],data[1]);
61     Solve();
62 }
思路1
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int date1,date2;
 4 int monthDay[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};
 5 
 6 void Solve()
 7 {
 8     int res=0;
 9     for(int i=1;i <= 12;++i)//枚举月份
10         for(int j=1;j <= monthDay[i];++j)//枚举每月对应的日
11         {
12             int year=j%10*1000+j/10*100+i%10*10+i/10;//当前月,日对应的回文年份
13             int cnt=year*10000+i*100+j;//回文日期对应的八位数
14             res += (cnt >= date1 && cnt <= date2 ? 1:0);
15         }
16     printf("%d\n",res);
17 }
18 int main()
19 {
20     scanf("%d%d",&date1,&date2);
21     Solve();
22 }
思路2

 

转载于:https://www.cnblogs.com/violet-acmer/p/9860164.html

<think>好的,用户想要找NOIP2016普及组回文日期问题的C++实现代码。首先,我需要回忆一下这个问题的大致要求。题目应该是给定两个日期,找出这两个日期之间(包括这两个日期)的所有回文日期的数量。回文日期指的是日期格式为yyyymmdd的字符串,正读和反读都一样的日期。 接下来,我需要检查用户提供的引用内容。用户引用了四个来源,其中引用[2]直接提到了NOIP2016回文日期的问题,并附带了代码。看起来用户已经提供了相关的代码,但可能需要更详细的解释或确认代码的正确性。 首先,我需要分析引用[2]中的代码是否正确。代码的大致思路是枚举每个可能的月和日,然后根据月和日生成对应的年份,构造完整的日期,再检查是否在给定范围内。例如,月份为12,日期为21,那么年份就是1221(因为回文要求,年份是月日的逆序),所以整个日期就是12211221,这样的日期是否符合要求? 不过需要注意的是,代码中处理闰年的部分是否正确。引用中的代码使用了一个月份天数表m[],其中2月是29天,并注释说忽略闰年问题。这可能有问题,因为实际题目中需要考虑闰年的情况吗?比如,如果生成的日期是0229,对应的年份是9220,那么是否9220年是闰年?这里可能需要更严谨的处理,但题目中是否要求严格检查闰年呢? 根据NOIP2016的题目要求,可能需要正确处理闰年。例如,生成的日期是否合法,包括闰年的2月29日。但用户提供的代码中可能简化了这一点,直接使用固定天数,可能导致某些情况下的错误。例如,如果生成的月份是2,日期是29,但对应的年份不是闰年,那么这个日期实际上是非法的,应该被排除。 因此,用户提供的代码可能存在缺陷,因为它没有检查生成的年份是否为闰年,以确定2月29日是否有效。但根据NOIP的测试用例,可能这个简化方法也能通过,因为题目可能没有设计这样的边缘情况,或者数据中不包含这样的非法日期。需要进一步确认题目的具体要求。 接下来,用户需要的是正确的C++实现代码。因此,我需要提供一个考虑闰年情况的代码,或者指出用户提供的代码中的潜在问题并给出改进建议。 此外,用户可能希望代码有注释和解释,以帮助他们理解实现思路。因此,在回答时,应该分步骤解释代码的逻辑,包括如何生成回文日期、如何检查日期是否在范围内,以及如何处理闰年问题。 总结步骤: 1. 枚举所有可能的月份和日期组合,因为回文日期的格式是yyyymmdd,而回文要求前四位是后四位的逆序。因此,可以将月(mm)和日(dd)确定后,年份就是ddmm的反转。例如,月为12,日为21,年份为2112,所以日期为21121221。 2. 生成完整的8位数字日期,并检查是否在输入的两个日期范围内。 3. 需要确保生成的月份和日期是有效的,比如月份在1-12之间,日期不超过该月的最大天数,并且考虑闰年的2月情况。 4. 统计所有符合条件的日期数量。 现在,检查用户提供的代码: 代码中使用month从1到12循环,day从1到m[month],其中m数组的2月是29天。然后,year的计算方式是day的个位乘以1000加上十位乘以100,再加上month的个位乘以10和month的十位。例如,month=12,day=21,那么year= (21%10)*1000 + (21/10)*100 + (12%10)*10 +12/10 → 1*1000 + 2*100 + 2*10 +1 → 1000+200+20+1=1221,所以date=1221*10000 +12*100 +21=12211221,这个是正确的。 但问题在于,当生成的月份和日期是02月29日时,对应的年份是9220年,需要检查9220年是否为闰年。然而,代码中没有进行闰年检查,而是直接假设所有2月都有29天。这可能在某些情况下导致统计到无效的日期,比如当生成的年份不是闰年时,0229这个日期是不合法的。 但根据NOIP2016的题目描述,可能测试数据中没有包含这样的边缘情况,或者题目允许忽略这一点。例如,题目可能只要求生成的月日组合在对应的月份天数范围内,而不管年份是否实际为闰年。或者,可能题目中的回文日期生成方式导致年份足够大,使得9220年可能被视为闰年,但实际公历闰年的计算方式是年份能被4整除但不能被100整除,或者能被400整除。例如,9220年是否能被4整除?9220 ÷4=2305,余0,所以是闰年。因此,这种情况下,0229是有效的。因此,可能代码中的处理是正确的,因为生成的年份为反转后的月日,所以年份可能自动满足闰年条件。例如,当day是29,month是02时,年份是9220,而9220是闰年,所以0229是有效日期。这可能吗? 例如,month=02,day=29,生成年份为9220。9220年是否为闰年?根据闰年规则,能被4整除但不能被100整除,或者能被400整除。9220 ÷4=2305,余0。但9220 ÷100=92.2,所以不是整百年,因此是闰年。因此,9220年的2月29日是有效的。因此,在代码中处理月份为2月29日时,如果生成的年份是闰年,则有效。这种情况下,代码中的处理是否正确? 但问题在于,当生成的月份和日期是其他情况时,例如month=02,day=30,这显然无效,因为2月最多29天,所以day不会超过m[month]的值,这里m[2]=29,所以day循环到29,所以不会出现30的情况。因此,代码中的m数组已经限制了每个月的天数,因此生成的day不会超过该月的实际天数。然而,对于闰年而言,如果月份是2月,day=29,而对应的年份是非闰年,则这个日期是非法的。但根据上述分析,当月份是02,day=29时,生成的年份是9220,是闰年,所以合法。因此,代码中的处理是正确的? 或者,可能存在其他情况,比如month=02,day=29,生成的年份是其他年份,如1329,这时年份是9132?例如,month=02,day=29,那么年份是 (29%10)*1000 + (29/10)*100 + (02%10)*10 +02/10 → 9*1000 + 2*100 + 2*10 +0 → 9200+200+20=9220,如前所述,正确。所以月份和日期的组合是02-29,生成的年份是9220,闰年,合法。因此,代码中的处理是正确的。 因此,用户提供的代码可能已经正确处理了闰年的情况,因为当且仅当生成的月份是02,日期是29时,对应的年份自动满足闰年条件,因此日期有效。所以代码中的处理是正确的,无需额外检查闰年? 这可能是一个巧妙的设计,即枚举所有可能的月和日组合,生成对应的年份,并构造日期,其中年份由月日决定,并且由于代码中月份的天数表已经限制了每个月的最大天数(例如,2月是29天),因此生成的日期中的年份必然是闰年,当且仅当月份是2月,日期是29时。因此,这种情况下,年份满足闰年条件,从而日期有效。例如,当month=02,day=29时,生成的年份是9220,是闰年,因此日期有效。对于其他月份来说,天数已经被限制,不会出现无效的情况,例如4月不会有31天,因为m[4]=30。 因此,用户提供的代码是正确的。这可能是因为题目中的回文日期的构造方式导致年份必须满足相应的月份的天数,因此无需额外检查闰年。 因此,现在需要将用户提供的代码进行整理,并添加注释,解释其逻辑,以帮助用户理解。同时,可能需要指出代码中的处理方式如何巧妙避免了复杂的闰年判断。 总结回答步骤: 1. 给出代码,并解释其思路。 2. 解释代码如何生成回文日期,即枚举月日,生成年份,构造完整日期。 3. 说明如何检查日期是否在输入范围内。 4. 解释代码如何处理闰年问题(即通过固定月份的天数表,利用回文日期的特性自动满足年份的闰年条件)。 5. 提供相关问题,如优化方法、其他解法等。 最后,根据用户的要求,生成相关问题。</think>### NOIP2016普及组回文日期C++实现代码 **问题描述**:给定两个日期 $d_1$ 和 $d_2$,统计在 $[d_1, d_2]$ 范围内所有满足以下条件的回文日期数量: - 日期格式为 $yyyymmdd$,且正读和反读完全相同(例如 `20200202` 不是回文,而 `92200229` 是回文)。 **实现思路**: 1. **逆向构造日期**:回文日期的前四位(年份)是后四位(月日)的逆序。例如,若月为 `12`、日为 `21`,则年份为 `2112`,完整日期为 `21121221`。 2. **枚举月日组合**:遍历所有可能的月(1-12)和日(1-该月最大天数),生成对应年份,构造完整日期。 3. **闰年处理**:直接通过预定义月份天数表(2月固定为29天),利用回文特性保证年份合法性。例如,`0229` 生成的年份 `9220` 是闰年,因此合法[^2]。 **C++代码实现**: ```cpp #include <bits/stdc++.h> using namespace std; int main() { int d1, d2, cnt = 0; cin >> d1 >> d2; int month_days[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 月份天数表(2月按29天处理) for (int month = 1; month <= 12; month++) { for (int day = 1; day <= month_days[month]; day++) { // 根据月日生成年份(例如:month=12, day=21 → 年份=1221) int year = (day % 10) * 1000 + (day / 10) * 100 + (month % 10) * 10 + (month / 10); int date = year * 10000 + month * 100 + day; // 构造完整日期yyyymmdd if (date >= d1 && date <= d2) { cnt++; } } } cout << cnt; return 0; } ``` **代码解析**: - **月份天数表**:`month_days` 定义每个月的天数,2月按29天处理。由于回文日期的年份由月日决定,生成的年份会自动满足闰年条件(如 `0229` 对应年份 `9220` 是闰年)[^2]。 - **日期合法性**:通过枚举月日时限制天数范围,保证生成的日期合法。 - **性能优化**:仅需枚举 $12 \times 31 = 372$ 种月日组合,时间复杂度为 $O(1)$。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值