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 }
时间: 2024-10-10 12:24:52

ZOJ 3950 - How Many Nines的相关文章

ZOJ How Many Nines 模拟 | 打表

How Many Nines Time Limit: 1 Second      Memory Limit: 65536 KB If we represent a date in the format YYYY-MM-DD (for example, 2017-04-09), do you know how many 9s will appear in all the dates between Y1-M1-D1 and Y2-M2-D2 (both inclusive)? Note that

ZOJ 17届校赛 How Many Nines

If we represent a date in the format YYYY-MM-DD (for example, 2017-04-09), do you know how many 9s will appear in all the dates between Y1-M1-D1 and Y2-M2-D2(both inclusive)? Note that you should take leap years into consideration. A leap year is a y

概率dp ZOJ 3640

Help Me Escape Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status Practice ZOJ 3640 Appoint description:  System Crawler  (2014-10-22) Description Background     If thou doest well, shalt thou not be accepted? an

zoj 2156 - Charlie&#39;s Change

题目:钱数拼凑,面值为1,5,10,25,求组成n面值的最大钱币数. 分析:dp,01背包.需要进行二进制拆分,否则TLE,利用数组记录每种硬币的个数,方便更新. 写了一个 多重背包的 O(NV)反而没有拆分快.囧,最后利用了状态压缩优化 90ms: 把 1 cents 的最后处理,其他都除以5,状态就少了5倍了. 说明:貌似我的比大黄的快.(2011-09-26 12:49). #include <stdio.h> #include <stdlib.h> #include <

ZOJ 1718 POJ 2031 Building a Space Station 修建空间站 最小生成树 Kruskal算法

题目链接:ZOJ 1718 POJ 2031 Building a Space Station 修建空间站 Building a Space Station Time Limit: 2 Seconds      Memory Limit: 65536 KB You are a member of the space station engineering team, and are assigned a task in the construction process of the statio

ZOJ 3607 Lazier Salesgirl (贪心)

Lazier Salesgirl Time Limit: 2 Seconds      Memory Limit: 65536 KB Kochiya Sanae is a lazy girl who makes and sells bread. She is an expert at bread making and selling. She can sell the i-th customer a piece of bread for price pi. But she is so lazy

ZOJ - 2243 - Binary Search Heap Construction

先上题目: Binary Search Heap Construction Time Limit: 5 Seconds      Memory Limit: 32768 KB Read the statement of problem G for the definitions concerning trees. In the following we define the basic terminology of heaps. A heap is a tree whose internal n

ZOJ 2859 二维线段树

思路:自己写的第二发二维线段树1A,哈哈,看来对二维的push操作比较了解了:但是还没遇到在两个线段树中同时进行push操作的,其实这题我是想在x维和y维同时进行push操作的,但是想了好久不会,然后看到这题又给出10秒,然后想想在x维线段直接单点查询肯定也过了,然后在第二维就只有pushup操作,在第一维线段树没有pushup操作.要是在第一维也有pushup操作的话,那就不用单点查询那么慢了.不过也A了,想找题即在二维同时进行pushup和pushdown操作的. #include<iost

ZOJ 2588

求一个无向图的桥(可能存在重边),输出割边的数目,并按顺序输出割边的序号(输入的顺序). 由于内存的限制 , 无法使用邻接矩阵 , 只能用邻接表了 . 第一次用了邻接表,超内存了: 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <string.h> 5 using namespace std; 6 const int N=10002; 7 const i