回文日期(两种方法,牛客)
题目描述
众所周知,小K是nowcoder的暴政苟管理,所以小K很擅长踢树,虽然本题与踢树无关
小K喜欢将日期排列成yyyy-mm-dd的形式(位数不足添零补齐)的形式,虽然这与小K只会做回文字符串这道水题无关,但小K觉得日期组成的回文串也是挺可爱的。作为一个凉心出题人,小K决定给你一个可爱的问题:给你两个日期,求这两个日期的闭区间内有多少个回文的日期(输入可能包含多组数据)
输入描述:
第一行包含一个整数T,表示有T组数据
接下来T行,每行两个“yyyy-mm-dd"形式的日期
输出描述:
输出共T行,每行输出当前数据的回文日期的个数
示例1
输入
1 1926-08-16 2333-12-21
输出
36
备注:
对于100%的数据,1 ≤ 𝑇 ≤ 10,且日期的形式一定是 YYYY-MM-DD,且输 入日期一定合法,保证答案的年份不会超过4位
//两种方法,第一种是我自己的复杂无脑版,第二种是大神的方法 //@第一种: /* 思路:每一个日期都检验一次(没第二种方法好) */ #include<bits/stdc++.h> #define ll long long using namespace std; int main() { ll t,k,y,r,n,m; ll ans=0;//k为年,y为月,r为日,ans为答案 ll s[13]={0,31,29,31,30,31,30,31,31,30,31,30,31}; //s的第0位没有,从1到12位分别为一个月的天数 scanf("%lld",&t); while(t--) { scanf("%lld-%lld-%lld",&k,&y,&r);//输入初始天数 n=k*10000+y*100+r;//把一个年份变成一个数字 //比如1926-08-16=>八位数19260816 scanf("%lld-%lld-%lld",&k,&y,&r);//输入结尾天数 m=k*10000+y*100+r; ans=0; for(;n<=m;n++)//从起始日期遍历到截止日期 { ll yue=n/100%10+n/1000%10*10;//计算当前月 ll r=s[yue];//计算当前最大限度的日 if(n%10+n/10%10*10>r)//如果日超出了 {//比如7月有31天,现在到32天,就要减去 n-=r; n+=100;//而且月份要加一 } if(n/100%10+n/1000%10*10>=13) {//同理,如果月份超出12了 n-=1200;//月份回归到1 n+=10000;//年加一 } if(n/10000000==n%10&&n/1000000%10==n/10%10&&n/100000%10==n/100%10&&n/10000%10==n/1000%10) ans++;//判断是否为回文串 } printf("%lld\n",ans); } return 0; } //@第二种: //感谢牛客网 Cyhlnj 的代码 //下面的代码都是复制他的,手动膜拜 /* 思路: 生成1月1日到12月31日的所有回文串八位数,不管是否合法,不管大学在不在要求内 那么一共大约会有30*12=360个数 再每个数跑一遍是否在n到m内 (降维打击,从回文串本质出发,考虑到月份一共才12个,日最多31,所以用这种方法,膜拜) */ #include<bits/stdc++.h> using namespace std; int i,j,n,m,a,b,c,sum,ans,t; int s[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};//预备每个月日期 int main() { scanf("%d",&t); while(t--) { scanf("%d-%d-%d",&a,&b,&c);//这几行同上 n=a*10000+b*100+c; scanf("%d-%d-%d",&a,&b,&c); m=a*10000+b*100+c; ans=0; for (i=1;i<=12;i++)//i为月从1到12 for (j=1;j<=s[i];j++)//j为日从1到s[i] { c=(j%10)*1000+(j/10)*100+(i%10)*10+(i/10); //举栗子:如果现在是i为12,j为08; //即12月08日 //那么c=8021相当于生成一个底朝天的数 sum=c*10000+i*100+j;//sum=80211208 if (sum<n||sum>m) continue;//如果这个数字不在n到m之间就下一个 ans++;//如果在的话就ans++ //ps:这方法太巧妙了 } printf("%d\n",ans);//输出答案 } return 0; }