zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ", 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

    其实一开始为什么不直接用sum[i][j][k]呢,是因为没想到,

    以前比较日期大小,是直接i * 1000000 + j * 10000 + k * 10之类的hash,这样方便比较日期的大小,但是这样的下标就会非常大,需要hash,比较麻烦,所以就没用这个了。没想到用三维表示。其实hash也就是一个数组而已吧。

    #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 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++;
        }
    }
    int sum[10000 + 2][14][35];
    int cnt(int val) {
        int ans = 0;
        while (val / 10 > 0) {
            ans += val % 10 == 9;
            val /= 10;
        }
        ans += val == 9;
        return ans;
    }
    void init() {
        for (int i = 1; i <= 9999; ++i) {
            for (int j = 1; j <= 12; ++j) {
                for (int k = 1; k <= has[j] + isyear(i); ++k) {
                    int preY = i, preM = j, preD = k;
                    cut(preY, preM, preD);
                    sum[i][j][k] = sum[preY][preM][preD];
                    sum[i][j][k] += cnt(i);
                    sum[i][j][k] += j == 9;
                    sum[i][j][k] += k % 10 == 9;
                }
            }
        }
    }
    void work() {
        int beY, beM, beD, enY, enM, enD;
        scanf("%d%d%d%d%d%d", &beY, &beM, &beD, &enY, &enM, &enD);
        cut(beY, beM, beD);
        printf("%d
    ", sum[enY][enM][enD] - sum[beY][beM][beD]);
    }
    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

    code:  加个二分找pos,hash函数:i * 10000 + j * 100 + k

    #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 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++;
        }
    }
    int cnt(int val) {
        int ans = 0;
        while (val / 10 > 0) {
            ans += val % 10 == 9;
            val /= 10;
        }
        ans += val == 9;
        return ans;
    }
    int sum[10000 * 12 * 31 + 20];
    int tot[10000 * 12 * 31 + 20], to;
    int tohash(int a, int b, int c) {
        return a * 10000 + b * 100 + c;
    }
    void init() {
        for (int i = 1; i <= 9999; ++i) {
            for (int j = 1; j <= 12; ++j) {
                for (int k = 1; k <= has[j] + (isyear(i) && j == 2); ++k) {
                    tot[++to] = tohash(i, j, k);
                    sum[to] = sum[to - 1];
                    sum[to] += cnt(i);
                    sum[to] += j == 9;
                    sum[to] += k % 10 == 9;
                }
            }
        }
    }
    void work() {
        int beY, beM, beD, enY, enM, enD;
        scanf("%d%d%d%d%d%d", &beY, &beM, &beD, &enY, &enM, &enD);
        int res1 = tohash(beY, beM, beD);
        int res2 = tohash(enY, enM, enD);
        int posB = lower_bound(tot + 1, tot + 1 + to, res1) - tot;
        int posE = lower_bound(tot + 1, tot + 1 + to, res2) - tot;
    //    cout << posB << " " << posE << endl;
        printf("%d
    ", sum[posE] - sum[posB - 1]);
    }
    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
  • 相关阅读:
    Access的相关SQL语句
    决心创业
    [转]在.NET环境中使用单元测试工具NUnit
    [转]IE"单击以激活控件"网站代码解决法
    [转]C#中ToString格式大全
    [转]div中放flash运行30秒钟后自动隐藏效果
    Property和attribute的区别
    C++中的虚函数(virtual function)
    进程间通信方式
    关于页面传值的方法
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6686765.html
Copyright © 2011-2022 走看看