2021 年10月30日星期六

牛客网算法竞赛入门班第一节课习题

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;
}

以下是一个简单的C语言代码,可以根据给定的年份打印出该年份历。注释已经写在代码中,方便理解。 ```c #include <stdio.h> // 判断给定年份是否为闰 int isLeapYear(int year) { if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) { return 1; } return 0; } // 计算给定年份的每个份的天数 void getMonthDays(int year, int month, int *days) { int common_year[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int leap_year[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; if (isLeapYear(year)) { for (int i = 0; i < 12; i++) { days[i] = leap_year[i]; } } else { for (int i = 0; i < 12; i++) { days[i] = common_year[i]; } } } // 打印给定年份历 void printCalendar(int year) { int monthDays[12]; // 存储每个份的天数 getMonthDays(year, 0, monthDays); // 获取每个份的天数 printf("==================== %d ====================\n", year); printf("Sun\tMon\tTue\tWed\tThu\tFri\tSat\n"); int week = 0; // 记录当前日期的星期几 for (int i = 0; i < 12; i++) { printf("\n==================== %d ====================\n", i + 1); printf("Sun\tMon\tTue\tWed\tThu\tFri\tSat\n"); // 打印每个份的历 for (int j = 0; j < week; j++) { printf("\t"); } for (int j = 1; j <= monthDays[i]; j++) { printf("%d\t", j); week++; if (week == 7) { printf("\n"); week = 0; } } } } int main() { int year; printf("请输入一个年份:"); scanf("%d", &year); printCalendar(year); return 0; } ``` 使用时,先输入一个年份,程序会自动打印出该年份历。例如,输入2022,打印的结果如下: ``` 请输入一个年份:2022 ==================== 2022 ==================== Sun Mon Tue Wed Thu Fri Sat ==================== 1 ==================== Sun Mon Tue Wed Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ==================== 2 ==================== Sun Mon Tue Wed Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ==================== 3 ==================== Sun Mon Tue Wed Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ==================== 4 ==================== Sun Mon Tue Wed Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ==================== 5 ==================== Sun Mon Tue Wed Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ==================== 6 ==================== Sun Mon Tue Wed Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ==================== 7 ==================== Sun Mon Tue Wed Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ==================== 8 ==================== Sun Mon Tue Wed Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ==================== 9 ==================== Sun Mon Tue Wed Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ==================== 10 ==================== Sun Mon Tue Wed Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ==================== 11 ==================== Sun Mon Tue Wed Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ==================== 12 ==================== Sun Mon Tue Wed Thu Fri Sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值