标签:高达 ret 暴力 预处理 log cal 题目 for max
从Y1-M1-D1到Y2-M2-D2间所有日期,出现多少个9?
呃讲真,刚开始想这个题目还是很烦的,各种要考虑的情况……
最后思考这样:
对于任何输入,设输入分别为 st.y st.m st.d ed.y ed.m ed.d ,分成三种情况:
①st.y==ed.y,两个日期出现在同一年里,直接暴力查[st,ed]间出现多少个9;
②ed.y-st.y==1,两个日期出现在相邻年,直接查[st,st这一年的12.31]+[ed这一年的1.1,ed];
③ed.y-st.y>1,这样,除了②要查的,还要在加上中间那些一整年一整年出现了多少个9;
这样,我们就需要一个函数calc(year,month1,day1,month2,day2)来计算同一年内从某天到某天,这么多天里出现了多少个9
另外,我们还需要计算出中间那些整年整年的,出现了多少个9;
然后就有了如下超时代码:
1 #include<cstdio> 2 struct Date{ 3 int y,m,d; 4 }st,ed,mid; 5 int cnt; 6 int leap_md[13]={0,31,29,31,30,31,30,31,31,30,31,30,31}; 7 int not_leap_md[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; 8 bool is_leap_year(int year) 9 { 10 if(year%100==0) 11 { 12 if(year%400==0) return true; 13 else return false; 14 } 15 else 16 { 17 if(year%4==0) return true; 18 else return false; 19 } 20 } 21 int calc(int year,int m1,int d1,int m2,int d2) 22 { 23 int cnt=0; 24 25 for(int month=m1;month<=m2;month++) 26 { 27 28 if(month==m1) 29 { 30 int max_day=is_leap_year(year)?(leap_md[month]):(not_leap_md[month]); 31 for(int day=d1;day<=max_day;day++) 32 { 33 if(day%10 == 9) cnt++; 34 if(day/10 == 9) cnt++; 35 36 if(year%10 == 9) cnt++; 37 if(year/10%10 == 9) cnt++; 38 if(year/100%10 == 9) cnt++; 39 if(year/1000 == 9) cnt++; 40 41 if(month%10 == 9) cnt++; 42 if(month/10 == 9) cnt++; 43 } 44 } 45 else if(month==m2) 46 { 47 for(int day=1;day<=d2;day++) 48 { 49 if(day%10 == 9) cnt++; 50 if(day/10 == 9) cnt++; 51 52 if(year%10 == 9) cnt++; 53 if(year/10%10 == 9) cnt++; 54 if(year/100%10 == 9) cnt++; 55 if(year/1000 == 9) cnt++; 56 57 if(month%10 == 9) cnt++; 58 if(month/10 == 9) cnt++; 59 } 60 } 61 else 62 { 63 int max_day=is_leap_year(year)?(leap_md[month]):(not_leap_md[month]); 64 for(int day=1;day<=max_day;day++) 65 { 66 if(day%10 == 9) cnt++; 67 if(day/10 == 9) cnt++; 68 69 if(year%10 == 9) cnt++; 70 if(year/10%10 == 9) cnt++; 71 if(year/100%10 == 9) cnt++; 72 if(year/1000 == 9) cnt++; 73 74 if(month%10 == 9) cnt++; 75 if(month/10 == 9) cnt++; 76 } 77 } 78 } 79 return cnt; 80 } 81 int main() 82 { 83 int t; 84 scanf("%d",&t); 85 while(t--) 86 { 87 scanf("%d%d%d%d%d%d",&st.y,&st.m,&st.d,&ed.y,&ed.m,&ed.d); 88 if(st.y==ed.y) 89 { 90 printf("%d\n",calc(st.y ,st.m, st.d, ed.m, ed.d)); 91 continue; 92 } 93 else if(ed.y-st.y==1) 94 { 95 printf("%d\n",calc(st.y ,st.m, st.d, 12, 31)+calc(ed.y , 1, 1, ed.m, ed.d)); 96 continue; 97 } 98 else 99 { 100 int ans=0; 101 for(int year=st.y+1; year<=ed.y-1; year++) 102 { 103 if(is_leap_year(year)) ans+=66; 104 else ans+=65; 105 106 int cnt=0; 107 if(year%10 == 9) cnt++; 108 if(year/10%10 == 9) cnt++; 109 if(year/100%10 == 9) cnt++; 110 if(year/1000 == 9) cnt++; 111 cnt*=is_leap_year(year)?(366):(365); 112 113 ans+=cnt; 114 } 115 ans+=calc(st.y ,st.m, st.d, 12, 31)+calc(ed.y , 1, 1, ed.m, ed.d); 116 printf("%d\n",ans); 117 continue; 118 } 119 } 120 }
其中需要注意的是,一整年中:不看年,单纯月和日,9会出现66或65次(闰年/非闰年);加上年的,年份里9的个数*365或者366。
但是很不幸的就TLE了,定睛一看,测试数据高达1e5,我们算整年的循环,大概每个test最坏情况循环8000次不到一些,再乘上1e5,就会超过1s,就会T,所以我们要预处理整年整年的
1 #include<cstdio> 2 #include<cstring> 3 struct Date{ 4 int y,m,d; 5 }st,ed,mid; 6 int cnt; 7 int leap_md[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};//闰年的每一个月有多少天 8 int not_leap_md[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};//非闰年的每一个月有多少天 9 int num[10000]; 10 bool is_leap_year(int year) 11 { 12 if(year%100==0) 13 { 14 if(year%400==0) return true; 15 else return false; 16 } 17 else 18 { 19 if(year%4==0) return true; 20 else return false; 21 } 22 } 23 int calc(int year,int m1,int d1,int m2,int d2) 24 { 25 int cnt=0; 26 if(m1==m2)//前后日期在同一个月 27 { 28 for(int day=d1;day<=d2;day++) 29 { 30 if(day%10 == 9) cnt++; 31 if(day/10 == 9) cnt++; 32 33 if(year%10 == 9) cnt++; 34 if(year/10%10 == 9) cnt++; 35 if(year/100%10 == 9) cnt++; 36 if(year/1000 == 9) cnt++; 37 38 if(m1%10 == 9) cnt++; 39 if(m1/10 == 9) cnt++; 40 } 41 return cnt; 42 } 43 44 for(int month=m1;month<=m2;month++)//按月循环 45 { 46 47 if(month==m1)//特判开始日期所在月 48 { 49 int max_day=is_leap_year(year)?(leap_md[month]):(not_leap_md[month]); 50 for(int day=d1;day<=max_day;day++) 51 { 52 if(day%10 == 9) cnt++; 53 if(day/10 == 9) cnt++; 54 55 if(year%10 == 9) cnt++; 56 if(year/10%10 == 9) cnt++; 57 if(year/100%10 == 9) cnt++; 58 if(year/1000 == 9) cnt++; 59 60 if(month%10 == 9) cnt++; 61 if(month/10 == 9) cnt++; 62 } 63 } 64 else if(month==m2)//特判结束日期所在月 65 { 66 for(int day=1;day<=d2;day++) 67 { 68 if(day%10 == 9) cnt++; 69 if(day/10 == 9) cnt++; 70 71 if(year%10 == 9) cnt++; 72 if(year/10%10 == 9) cnt++; 73 if(year/100%10 == 9) cnt++; 74 if(year/1000 == 9) cnt++; 75 76 if(month%10 == 9) cnt++; 77 if(month/10 == 9) cnt++; 78 } 79 } 80 else//其他月份 81 { 82 int max_day=is_leap_year(year)?(leap_md[month]):(not_leap_md[month]); 83 for(int day=1;day<=max_day;day++) 84 { 85 if(day%10 == 9) cnt++; 86 if(day/10 == 9) cnt++; 87 88 if(year%10 == 9) cnt++; 89 if(year/10%10 == 9) cnt++; 90 if(year/100%10 == 9) cnt++; 91 if(year/1000 == 9) cnt++; 92 93 if(month%10 == 9) cnt++; 94 if(month/10 == 9) cnt++; 95 } 96 } 97 } 98 return cnt; 99 } 100 void pretreat()//预处理 101 { 102 memset(num,0,sizeof(num));//num[k]数组表示从2000年到k年,这么多个整年一天一天的出现了多少个9 103 for(int year=2000;year<=9999;year++) 104 { 105 int ans=0; 106 if(is_leap_year(year)) ans+=66; 107 else ans+=65; 108 109 int cnt=0; 110 if(year%10 == 9) cnt++; 111 if(year/10%10 == 9) cnt++; 112 if(year/100%10 == 9) cnt++; 113 if(year/1000 == 9) cnt++; 114 cnt*=is_leap_year(year)?(366):(365); 115 116 ans+=cnt; 117 118 num[year]=num[year-1]+ans; 119 } 120 } 121 int main() 122 { 123 pretreat(); 124 int t; 125 scanf("%d",&t); 126 while(t--) 127 { 128 scanf("%d%d%d%d%d%d",&st.y,&st.m,&st.d,&ed.y,&ed.m,&ed.d); 129 if(st.y==ed.y)//情况① 130 { 131 printf("%d\n",calc(st.y ,st.m, st.d, ed.m, ed.d)); 132 continue; 133 } 134 else if(ed.y-st.y==1)//情况② 135 { 136 printf("%d\n",calc(st.y ,st.m, st.d, 12, 31)+calc(ed.y , 1, 1, ed.m, ed.d)); 137 continue; 138 } 139 else//情况③ 140 { 141 int ans=num[ed.y-1]-num[st.y]; 142 ans+=calc(st.y ,st.m, st.d, 12, 31)+calc(ed.y , 1, 1, ed.m, ed.d); 143 printf("%d\n",ans); 144 continue; 145 } 146 } 147 }
标签:高达 ret 暴力 预处理 log cal 题目 for max
原文地址:http://www.cnblogs.com/dilthey/p/6837866.html