ZOJ 3950 - How Many Nines

Posted tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZOJ 3950 - How Many Nines相关的知识,希望对你有一定的参考价值。

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

 

以上是关于ZOJ 3950 - How Many Nines的主要内容,如果未能解决你的问题,请参考以下文章

ZOJ 3950 - How Many Nines

ZOJ How Many Nines 模拟 | 打表

ZOJ 17届校赛 How Many Nines

[省赛训练]How many nines

zoj——3557 How Many Sets II

ZOJ 3556 How Many Sets I