【NOIP2016普及组】回文日期

本文介绍了一个算法问题,即如何计算两个指定日期间的真实存在的回文日期数量。文章提供了一段C++代码示例,用于解析日期并判断这些日期是否符合回文特性。

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


题目描述

在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。

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

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

输入

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

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

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

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

保证date1—定不晚于date2。

输出

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

样例输入1

20110101

20111231

样例输出1

1

样例输入2

20000101
20101231

样例输出2

2

-My show time-

我的思路

先把首末位的年月日提炼出来,然后从开始年开始,到结束年生成一个本年的回文数,如果这个数是一个正确的日期啊啊!

我的代码

你们要的正确的代码(呃...只有c++的)

#include <iostream>
#include <string>
using namespace std;
 class _{
 	public:
 		int y;
 		int m;
 		int d;
 		string ymd;

 };
void split(string s,int &a,int &b,int &c){
			a=(s[0]-'0')*1000+(s[1]-'0')*100+(s[2]-'0')*10+(s[3]-'0');
			b=(s[4]-'0')*100+(s[5]-'0');
			c=(s[6]-'0')*100+(s[7]-'0');
					
		 }
bool run(int runnian)
{
	if(runnian%4==0&&runnian%100)return true;
	if(runnian%400==0)return true;
	return false;
}
int main()
{int tpl=0;
_ startday;
_ endday;
int nian,yue,ri;
cin>>startday.ymd>>endday.ymd;
split(startday.ymd,startday.y,startday.m,startday.d);
split(endday.ymd,endday.y,endday.m,endday.d);
int i,s;
int c=0;
for(i=startday.y;i<=endday.y;i++)
{
nian=i;
yue=(nian%10)*10+(nian/10%10);
ri=(nian/100%10)*10+(nian/1000%10);
c++;
s=0;
if(yue>12||yue<1||ri<1||ri>31)s=1;
if(yue==4||yue==6||yue==9||yue==11)if(ri>30)s=1;
if(run(nian)==false)if(yue==2)if(ri>28)s=1;
if(run(nian)==true)if(yue==2)if(ri>29)s=1;
if(nian==startday.y&&(yue<startday.m&&ri<startday.d))s=1;
if(nian==endday.y&&(yue>endday.m&&ri>endday.d))s=1;
c=c-s;}
cout<<c<<endl;} 

AC图来一套:


BYE~

<think>好的,用户想要找NOIP2016普及组回文日期问题的C++实现代码。首先,我需要回忆一下这个问题的大致要求。题目应该是给定两个日期,找出这两个日期之间(包括这两个日期)的所有回文日期的数量。回文日期指的是日期格式为yyyymmdd的字符串,正读和反读都一样的日期。 接下来,我需要检查用户提供的引用内容。用户引用了四个来源,其中引用[2]直接提到了NOIP2016回文日期的问题,并附带了代码。看起来用户已经提供了相关的代码,但可能需要更详细的解释或确认代码的正确性。 首先,我需要分析引用[2]中的代码是否正确。代码的大致思路是枚举每个可能的月和日,然后根据月和日生成对应的年份,构造完整的日期,再检查是否在给定范围内。例如,月份为12日期21,那么年份就是1221(因为回文要求,年份是月日的逆序),所以整个日期就是12211221,这样的日期是否符合要求? 不过需要注意的是,代码中处理闰年的部分是否正确。引用中的代码使用了一个月份天数表m[],其中2月是29天,并注释说忽略闰年问题。这可能有问题,因为实际题目中需要考虑闰年的情况吗?比如,如果生成的日期是0229,对应的年份是9220,那么是否9220年是闰年?这里可能需要更严谨的处理,但题目中是否要求严格检查闰年呢? 根据NOIP2016的题目要求,可能需要正确处理闰年。例如,生成的日期是否合法,包括闰年的229日。但用户提供的代码中可能简化了这一点,直接使用固定天数,可能导致某些情况下的错误。例如,如果生成的月份是2日期29,但对应的年份不是闰年,那么这个日期实际上是非法的,应该被排除。 因此,用户提供的代码可能存在缺陷,因为它没有检查生成的年份是否为闰年,以确定229日是否有效。但根据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,这个是正确的。 但问题在于,当生成的月份和日期是0229日时,对应的年份是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年的229日是有效的。因此,在代码中处理月份为229日时,如果生成的年份是闰年,则有效。这种情况下,代码中的处理是否正确? 但问题在于,当生成的月份和日期是其他情况时,例如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、付费专栏及课程。

余额充值