【模拟】回文日期

博客围绕求日期 AA 到日期 BB 之间的回文日期展开。先给出题目链接,阐述题目大意,接着介绍思路,尝试暴力模拟但超时,分析了二月日期判断情况,最后给出 AC 代码,其时间复杂度为 O(365)。

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

链接

https://www.luogu.org/problemnew/show/P2010

大意

求日期 A A 到日期B之间的会问日期
满足:
data=10000year+100month+day d a t a = 10000 y e a r + 100 m o n t h + d a y

1000<=year<=9999  1<=month<=12  day<=31 1000 <= y e a r <= 9999     1 <= m o n t h <= 12     d a y <= 31

思路

首先想一下暴力模拟,按题意枚举,但是。。。
超时了(可能是我代码打得丑)

暴力代码

时间复杂度: O(16×(9999123110000001)) O ( 16 × ( 99991231 − 10000001 ) )

#include<cstdio>
#define normal return year*10000+month*100+day+1
using namespace std;
int a,b,ans;
int c[13]={-1,1,2,1,0,1,0,1,1,0,1,0,1};//1表示31天的,0表示30天的
int r(int year)//闰年天数判断
{
    if(year%400==0) return 29;
    if(year%100&&year%4==0) return 29;
    return 28;
}
int special(int year,int month,int day)//若需要进位
{
    day=1;
    if(month==12) year++,month=1;else month++;
    normal;
}
int next(int x)//下一天
{
    int a[101]={0},j=0;
    while(x) a[++j]=x%10,x/=10;
    int year=a[8]*1000+a[7]*100+a[6]*10+a[5];
    int month=a[4]*10+a[3],day=a[2]*10+a[1];
    if(c[month]==1) if(day<31) normal; else return special(year,month,day);
    if(c[month]==0) if(day<30) normal; else return special(year,month,day);
    if(c[month]==2) if(day<r(year)) normal;else return special(year,month,day);
}
bool hw(int x)//判断会问
{
    int a[101]={0},j=0;
    while(x) a[++j]=x%10,x/=10;
    for(int i=1;i<<1<=j;i++) if(a[i]!=a[8-i+1]) return false;
    return true;
}
int main()
{
    scanf("%d%d",&a,&b);
    for(int i=a;i!=b;i=next(i)) ans+=hw(i);
    printf("%d",ans+hw(b));//输出
}

其实二月不用判断28日,直接运行到29日就行了,为什么呢,来看一波骚证明
若有一天的日期为2月28日,因为要满足会问的特性,这一天必然是82200228,满足要求
假设有一天的日期为2月29日,同理,这一天必然是92200229,而92200229这一年是闰年所以直接判断到29就行了

AC代码

时间复杂度: O()=O(365)=O(1) O ( 所 有 月 份 日 期 的 和 ) = O ( 365 ) = O ( 1 )

#include<cstdio>
using namespace std;int a,b,c,d,e,s,ans;
int data[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};
int main()
{
    scanf("%d%d",&a,&b);
    for(c=1;c<=12;c++)
     for(d=1;d<=data[c];d++)//枚举日期
     {
        e=(d%10)*1000+(d/10)*100+(c%10)*10+(c/10);//求出年份
        s=e*10000+c*100+d;
        if(s<a||s>b) continue;//判断
        ans++;
     }
    printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值