Light OJ 1414 February 容斥

1414 - February 29
Time Limit: 1 second(s)Memory Limit: 32 MB

It is 2012, and it's a leap year. So there is a "February 29" in this year, which is called leap day. Interesting thing is the infant who will born in this February 29, will get his/her birthday again in 2016, which is another leap year. So February 29 only exists in leap years. Does leap year comes in every 4 years? Years that are divisible by 4 are leap years, but years that are divisible by 100 are not leap years, unless they are divisible by 400 in which case they are leap years.

In this problem, you will be given two different date. You have to find the number of leap days in between them.

Input

Input starts with an integer T (≤ 550), denoting the number of test cases.

Each of the test cases will have two lines. First line represents the first date and second line represents the second date. Note that, the second date will not represent a date which arrives earlier than the first date. The dates will be in this format - "month day, year", See sample input for exact format. You are guaranteed that dates will be valid and the year will be in between 2 * 103 to 2 * 109. For your convenience, the month list and the number of days per months are given below. You can assume that all the given dates will be a valid date.

Output

For each case, print the case number and the number of leap days in between two given dates (inclusive).

Sample Input

Output for Sample Input

4

January 12, 2012

March 19, 2012

August 12, 2899

August 12, 2901

August 12, 2000

August 12, 2005

February 29, 2004

February 29, 2012

Case 1: 1

Case 2: 0

Case 3: 1

Case 4: 3

Note

The names of the months are {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November" and "December"}. And the numbers of days for the months are {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 and 31} respectively in a non-leap year. In a leap year, number of days for February is 29 days; others are same as shown in previous line.


PROBLEM SETTER: MD. ARIFUZZAMAN ARIF
SPECIAL THANKS: JANE ALAM JAN

    题意:闰年中的2.29日为leap day,给定两个日期,求出日期之间的leap day的天数。

    分析:暴力求取肯定超时。开始时采用了求取对两个日期之间进行处理判断的方法,非常之复杂且耗时易错。看过题解后,采用容斥原理求解,恍然大悟。以0年为起点,分别求取两个日期和起点之间的闰日的个数。采用容斥原理求解,闰日个数即为:(a/4)-(a/100)+(a/400)。

    这样分别求出起点到年份之间的年份个数,注意闰日个数是包含了该年份的。而求取两个日期之间的闰日个数,记截止日期到起点的闰日个数为b,记开始日期到起点的闰日个数为a。b-a所得结果即为不包括起始年份,但包括截止年份的闰日个数。此时就需要考虑,是否需要加上起始年份,而需要加上起始年份的情况就是起始年份是闰年,并且给出的月份不大于2,此时不管日期是多少都包含了一个闰日,需要加上起始年份。而截止年份若不是闰年,则不影响,若是闰年,若此时的月份小于二月,或者月份等于二月但给出的日期小于29,此时该年份 的闰日均不计数,需在原有基础上减一。见AC代码:

#include<stdio.h>
#include<string.h>
using namespace std;
char month[12][12]= {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November" , "December"};
int is_leap(int n)
{
	if(n%100==0)
		if(n%400==0)
			return 1;
		else return 0;
	if(n%4==0)
		return 1;
	return false;
}
int numleap(int a)
{
	return  (a/4)-(a/100)+(a/400);
}
int main()
{
	int T,k=0;
	scanf("%d",&T);
	while(T--)
	{
		k++;
		int years,yeare;
		//int a,b;
		//	scanf("%d%d",&a,&b);
		char ms[10],me[10];
		int ds,ys,de,ye,mms,mme;
		scanf("%s %d, %d",ms,&ds,&ys);
		for(int i=0; i<12; i++)
			if(strcmp(ms,month[i])==0)
			{
				mms=i+1;
				break;
			}
		scanf("%s %d, %d",me,&de,&ye);
		for(int i=0; i<12; i++)
			if(strcmp(me,month[i])==0)
			{
				mme=i+1;
				break;
			}
		int res=numleap(ye)-numleap(ys);//此时不包括起始年   包括了最终年 
		if(is_leap(ys))
		{
			if(mms<=2) //是闰年时  且月份不大于2 则加一  
				res++;
		}
		if(is_leap(ye)) // 若最终年 
		{
			if(mme<2||(mme==2&&de<=28))//存在这样的情况  则最后一年需要减去 
				res--;
		}
		printf("Case %d: %d\n",k,res);
	}
}
    敲比赛的时候实在心态不好,这样的问题冷静分析应是可以解决的。容斥原理需要多理解。

    特记下,以备后日回顾。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值