链接
https://www.luogu.org/problemnew/show/P2010
大意
求日期
A
A
到日期之间的会问日期
满足:
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×(99991231−10000001)) 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);
}