^

Young Anything I do that may help others, I'll post it here.

hihocoder 1148 — 2月29日

1 描述

给定两个日期,计算这两个日期之间有多少个2月29日(包括起始日期)。

只有闰年有2月29日,满足以下一个条件的年份为闰年:

  1. 年份能被4整除但不能被100整除

  2. 年份能被400整除

2 输入

第一行为一个整数T,表示数据组数。

之后每组数据包含两行。每一行格式为”month day, year”,表示一个日期。month为{“January”, “February”, “March”, “April”, “May”, “June”, “July”, “August”, “September”, “October”, “November” , “December”}中的一个字符串。day与year为两个数字。

数据保证给定的日期合法且第一个日期早于或等于第二个日期。

3 输出

对于每组数据输出一行,形如”Case #X: Y”。X为数据组数,从1开始,Y为答案。

4 实现

import re

months = ["January", "February", "March", "April",
          "May", "June", "July", "August",
          "September", "October", "November", "December"]
mdict = dict(zip(months, xrange(1, 13)))


def parse(s, mdict):
    mm, dd, yy = re.compile(r"^(\w{3,9})\s(\d{1,2}),\s(\d{4,10})$").match(s).groups()
    yy = int(yy)
    mm = mdict[mm]
    dd = int(dd)
    return (yy, mm, dd)


def is_leapYear(x):
    return x % 400 == 0 if x % 100 == 0 else x % 4 == 0


def nlpy(y):  # 找到离这个年份最近的下一个闰年
    y = y / 4 * 4 + 4  # 在python2中: 普通除(/)= 地板除(//)
    while not is_leapYear(y):
        y += 4
    return y


def nextLeap(t):  # 找到离该日期最近的下一个 2月29日
    y = t[0]
    if not is_leapYear(y):
        return (nlpy(y), 2, 29)
    elif t <= (y, 2, 29):
        return (y, 2, 29)
    else:
        return (nlpy(y), 2, 29)


def next(y, d):  # 返回离y最近的下一个d倍数字
    return y if y % d == 0 else y / d * d + d


def countYear(y1, y2):  # 计算两个年份之间有多少个闰年,采用交并集的思想
    c4 = (y2 - y1) / 4
    c100 = (next(y2, 100) - next(y1, 100)) / 100
    c400 = (next(y2, 400) - next(y1, 400)) / 400
    return c4 - c100 + c400


while True:
    try:
        couple = int(raw_input().strip())
        for i in xrange(couple):
            t1 = parse(raw_input().strip(), mdict)
            t2 = parse(raw_input().strip(), mdict)
            t2 = (t2[0], t2[1], t2[2] + 1)
            t1 = nextLeap(t1)
            t2 = nextLeap(t2)
            print('Case #%d: %d' % (i + 1, countYear(t1[0], t2[0])))
    except EOFError:
        break

if __name__ == '__main__':  # 原来hihocoder不用一直循环输入,只做一次测试输入就行
    couple = int(raw_input().strip())
    for ci in xrange(couple):
        t1 = parse(raw_input().strip(), mdict)
        t2 = parse(raw_input().strip(), mdict)
        t2 = (t2[0], t2[1], t2[2] + 1)
        t1 = nextLeap(t1)
        t2 = nextLeap(t2)
        print('Case #%d: %d' % (ci + 1, countYear(t1[0], t2[0])))

5 总结

  1. python2.7.6print()输出(a tuple)
  2. python2.7.6应该尽量用xrange
  3. python2.7.6的普通除(/)= 地板除(//)
  4. 原来hihocoder不用一直循环输入,只做一次测试输入就行
  5. 简介的分支语句实现x % 400 == 0 if x % 100 == 0 else x % 4 == 0
  6. re.sub()替换可以写在re.split()函数参数里面传入:re.split('\s+', re.sub(',', '', aString))(其返回list
  7. re.compile(r"^(\w*) (\d*), (\d*)$").match(aString).groups()更优雅(其返回tuple
  8. 应该先思考,再下笔!