首页 > 代码库 > ZOJ 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 you should take leap years into consideration. A leap year is a year which can be divided by 400 or can be divided by 4 but can‘t be divided by 100.

Input

The first line of the input is an integer T (1 ≤ T ≤ 105), indicating the number of test cases. Then T test cases follow. For each test case:

The first and only line contains six integers Y1M1D1Y2M2D2, their meanings are described above.

It‘s guaranteed that Y1-M1-D1 is not larger than Y2-M2-D2. Both Y1-M1-D1 and Y2-M2-D2 are between 2000-01-01 and 9999-12-31, and both dates are valid.

We kindly remind you that this problem contains large I/O file, so it‘s recommended to use a faster I/O method. For example, you can use scanf/printf instead of cin/cout in C++.

Output

For each test case, you should output one line containing one integer, indicating the answer of this test case.

Sample Input

4
2017 04 09 2017 05 09
2100 02 01 2100 03 01
9996 02 01 9996 03 01
2000 01 01 9999 12 31

Sample Output

4
2
93
1763534

Hint

For the first test case, four 9s appear in all the dates between 2017-04-09 and 2017-05-09. They are: 2017-04-09 (one 9), 2017-04-19 (one 9), 2017-04-29 (one 9), and 2017-05-09 (one 9).

For the second test case, as year 2100 is not a leap year, only two 9s appear in all the dates between 2100-02-01 and 2100-03-01. They are: 2017-02-09 (one 9) and 2017-02-19 (one 9).

For the third test case, at least three 9s appear in each date between 9996-02-01 and 9996-03-01. Also, there are three additional nines, namely 9996-02-09 (one 9), 9996-02-19 (one 9) and 9996-02-29 (one 9). So the answer is 3 × 30 + 3 = 93.


Submit    Status

 

这题其实用一个数组int sum[10000][12][31]表示前缀和,第i年,第j个月,第k天有多少个合法情况。

然后区间减法即可。

不过我做的时候没想到这样,直接用模拟,wa良久。

我是先把begin的年份一直暴力向后算,算到新一年的1月1号,然后end的也一直向前算,算到那一年的1月一号。

然后直接对年份前缀和即可。然后边界很难处理。烦。。

如果能提交要再写一次。

技术分享
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;


#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
bool isyear(int val) {
    if (val % 400 == 0) return true;
    if (val % 4 == 0 && val % 100 != 0) return true;
    return false;
}
int has[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
void add(int &year, int &month, int &day) {
    day++;
    int t = has[month];
    if (month == 2 && isyear(year)) t++;
    if (day > t) {
        day = 1;
        month++;
        if (month > 12) {
            year++;
            month = 1;
        }
    }
}
void cut(int &year, int &month, int &day) {
    if (day != 1) day--;
    else {
        if (month == 1) {
            month = 12;
            year--;
        } else month--;
        day = has[month];
        if (month == 2 && isyear(year)) day++;
    }
}
bool toless(int year1, int month1, int day1, int year2, int month2, int day2) {
    if (year1 < year2) return true;
    if (month1 < month2) return true;
    if (day1 < day2) return true;
    return false;
}
int cnt(int val) {
    int ans = 0;
    while (val / 10 > 0) {
        ans += val % 10 == 9;
        val /= 10;
    }
    ans += val == 9;
    return ans;
}
LL sum[9999 + 20];
void work() {
    int year1, month1, day1;
    int year2, month2, day2;
    scanf("%d%d%d%d%d%d", &year1, &month1, &day1, &year2, &month2, &day2);
    LL ans = 0;
    while (toless(year1, month1, day1, year2, month2, day2)) {
        if (month1 == 1 && day1 == 1) {
            break;
        }
        if (month1 == 9) ans++;
        if (day1 % 10 == 9) ans++;
        ans += cnt(year1);
        add(year1, month1, day1);
    }
    while (toless(year1, month1, day1, year2, month2, day2)) {
        bool flag = false;
        if (month2 == 1 && day2 == 1) {
            flag = true;
        }
        if (month2 == 9) ans++;
        if (day2 % 10 == 9) ans++;
        ans += cnt(year2);
        if (flag) break;
        cut(year2, month2, day2);
    }
    if (!(month1 == 1 && day1 == 1)) { //样例一的情况,移动去不了1月1号
        if (month1 == 9) ans++;
        if (day1 % 10 == 9) ans++;
        ans += cnt(year1);
        printf("%lld\n", ans);
        return;
    }
    if (year1 == year2) { //1987 12 28   1988 1 1
        ans += cnt(year1);
    }
//    cout << year1 << " " << month1 << " " << day1 << endl;
//    cout << year2 << " " << month2 << " " << day2 << endl;
    ans += sum[year2 - 1] - sum[year1 - 1];
    printf("%lld\n", ans);
}
void init() {
    int year = 1;
    while (year <= 9999) {
        sum[year] += sum[year - 1];
        sum[year] += cnt(year) * (365 + isyear(year));
        sum[year] += 30;
        sum[year] += 3 * 11;
        sum[year] += 2 + isyear(year);
        year++;
    }
}
int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    init();
    int t;
    scanf("%d", &t);
    while (t--) work();
    return 0;
}
View Code

 

ZOJ How Many Nines 模拟 | 打表