牛客网算法竞赛入门班第一节课习题
NOIP2016 回文日期,两种写法,正常枚举,暴力打表
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
题目描述
在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。
牛牛习惯用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位数字。 第一行表示牛牛指定的起始日期。 第二行表示牛牛指定的终止日期。 保证datei和都是真实存在的日期,且年份部分一定为4位数字,且首位数字不为0。 保证date1 —定不晚于date2。
输出描述:
输出一行,包含一个整数,表示在date1和date2之间,有多少个日期是回文的。
实现代码:
1.枚举
思路:这个思路是这样的:当一个年份确定时,他的回文日期有且唯一,举个例 子 如果年是2021年,那么唯一的一个回文日期就是20211202,那么我们只需要来判断 后面的1202在不在范围内就可以了。
下面是代码:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int M[20]={0,31,0,31,30,31,30,31,31,30,31,30,31};
bool isLeapYear(int y)//该函数用于判定是否为闰年
{
if((y%4==0&&y%100!=0)||y%400==0)
return true;
return false;
}
bool check(int y)//粗筛数据,先检查一下符不符合最简单的日期要求
{
int m,d;
m=(y%10)*10+((y/10)%10);//回文后表示月
d=((y/1000)%10)+((y/100)%10)*10;//回文后表示天
if(m>12||m==0||d==0)
return false;
if(m==2)
{
if(isLeapYear(y))
M[2]=29;
else if(!isLeapYear(y))
M[2]=28;
}
if(d>M[m])
return false;
else
return true;
}//粗筛数据,至少确定数据符合日期格式
int ReYear(int y)
{
return (y%10)*1000+((y/10)%10)*100+((y/100)%10)*10+((y/1000)%10);
}
//所有函数都写完了,现在写主函数
int main()
{
int y1,md1;
int y2,md2;
scanf("%4d%4d",&y1,&md1);
scanf("%4d%4d",&y2,&md2);//以两个数的形式输入
int ans=0;
if(y1!=y2)
{
bool flag;
for(int i=y1+1;i<=y2-1;i++)
{
int m,d;
if(check(i))
ans++;
}
if(check(y1)&&md1<=ReYear(y1))
ans++;
if(check(y2)&&md2>=ReYear(y2))
ans++;
}
else
{
int m1,d1;
m1=(y1%10)*10+(y1/10)%10;
d1=((y1/1000)%10+((y1/100)%10)*10);
if(check(y1)&&ReYear(y1)>=md1&&ReYear(y1)<=md2)
{
ans++;
}
}
cout<<ans;
return 0;
}
2.模拟
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e4+7;
int ans=0,l,r,flag;
void check(int x){
if(x%10!=x/10000000) return;
if((x%100)/10!=(x/1000000)%10) return;
if((x%1000)/100!=(x/100000)%10) return;
if(x%10000/1000!=(x/10000)%10) return;
ans++;
}//判断回文日期
int main(){
scanf("%d%d",&l,&r);
for(int i=l;i<=r;i++){
int day=i%100,mon=(i%10000)/100,year=i/10000;
if(day>31||mon>12||mon==0||day==0) continue;
if(year%400==0||(year%100!=0&&year%4==0)) flag=1;
else flag=0;//flag标注闰年
if(mon==2){
if(flag==1){
if(day<30) check(i);
}else if(day<29) check(i);
}else if(mon==1||mon==3||mon==5||mon==7||mon==8||mon==10||mon==12){
if(day<32) check(i);
}else{
if(day<31) check(i);
}
}
cout<<ans;
return 0;
}
#include<iostream>
using namespace std;
int r[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};//月份从一月开始,数组中一月的天数就存在r[1]中;
//因为是直接通过月日回文来找年,所以2月直接存29,不用进行闰年判断;
int main(){
int m,n,sum,number=0;
cin>>m>>n;//输入两个端点; </iostream>
for(int i=1;i<=12;i++)
for(int j=1;j<=r[i];j++){
int c=j%10*1000+j/10*100+i%10*10+i/10;
int sum=c*10000+i*100+j;
//将所有的回文日期全部例举出来,通过if判断计数;
if(sum>=m&&sum<=n){
number++;
} }
cout<<number<<endl;//输出计数即可;
return 0;
}