HDU - 1201 - 18岁生日

https://vjudge.net/problem/HD...

一句话题意:给定出生日期(格式为1988-03-07),求到18岁生日为止经历了多少天;没有18岁生日输出-1。

这个题目太普通了,类似的问题可能满大街都是。这不是一个算法竞赛等级的题目,但是还是有的好说。我要记录的是我做这题的思考方式。

解:

首先考虑闰年。一般来说,公元闰年的确定方法如下:年份若为400的正整倍数时,闰;否则,年份是4的正整倍数且不是100的正整倍数时,闰;都不符合,平。这点体现在函数is_leap里。

我发现,若今年是闰年,日期在2月29日之前或之后的两种情形到“明年今日”的天数是不同的。如2008-03-012009-03-01经历366天,2008-02-282009-02-28经历365天。

对称地,若今年是平年,明年是闰年也有类似的规律可说。

这就是我要记录的“局部分离思想”。这个问题一开始看很复杂,但是我们发现,这一年到下一年,无非只有3种大情形。日期在2月29日之前简记为“前”;日期在这之后(含)简记为“后”。列表如下。

  1. 平=>平 前365天;后365天

  2. 平=>闰 前365天;后366天

  3. 闰=>平 前366天;后365天

这样一来,问题就迎刃而解了。

代码如下。

//AC,0ms;
#ifdef LOCAL
    #include<ctime>
#endif
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<sstream>
#include<algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#define LL long long
using namespace std;
int is_leap(int a){
    if(a%100 == 0) return !(a%400);
    else return !(a%4);
}
int main(){
#ifdef LOCAL
    freopen("in.txt","r",stdin);
    clock_t start, end;
    start = clock();
#endif
    int t;
    cin >> t;
    string s;
    while(t--){
        int y,m,d,modify=0,after=1;
        cin >> y >> m >> d;
        m=-m;
        d=-d;
        if(m == 2 && d == 29){
            cout << -1 << endl;
            continue;
        }else if(m<=2 && d<=28) after = 0;
        for(int i = y;i<=y+17;i++){
            if(is_leap(i)){
                if(!after){
                    modify++;
                }
            }else{
                if(is_leap(i+1)){
                    if(after){
                        modify++;
                    }
                }
            }
        }
        cout << modify + 365*18 << endl;
    }
#ifdef LOCAL
    end = clock();
    cout << "*************************" << endl;
    cout<< "Computing time: "<<(double)(end - start)*1000 / CLOCKS_PER_SEC<<"ms"<<endl;
#endif
    return 0;
}

我这里采用了增量的形式,在18*365天的基础上加上多出来的那几天。为啥只取到y+17呢?因为我们只用考虑这一年变到下一年的情形。第18年不会再变到下一年,所以只计算到y+17为止。


suicca
82 声望2 粉丝

为在座的各位献上一曲WHITE ALBUM (WRONG ANSWER)