其他分享
首页 > 其他分享> > swust oj 题解#509 寝室扫地问题(保姆级教学)

swust oj 题解#509 寝室扫地问题(保姆级教学)

作者:互联网

目录

题目

思路解析

代码实现


题目

思路解析

按照这个题的思路,我们不妨做一个2007年的日历

然后根据题目要求,排出扫地的人

MonTueWedThuFriSatSun
9月1(B)2(X)
3(ALL)4(H)5(P)6(B)7(X)8(H)9(P)
10(ALL)11(B)12(X)13(H)14(P)15(B)16(X)
17(ALL)18(H)19(P)20(B)21(X)22(H)23(P)
24(ALL)25(B)26(X)27(H)28(P)29(B)30(X)
10月1(ALL)2(H)3(P)4(B)5(X)6(H)7(P)
8(ALL)9(B)10(X)11(H)12(P)1314
15(ALL)161718192021
222324252627

28

293031
11月1234

想必根据表格,已经找出规律了吧,也就是14天一个轮回。 因此,愉快的开始打表生活

//c++ 代码
string name[14]={"B","X","ALL","H","P","B","X","H","P","ALL","B","X","H","P"};//打表输入人 
//c语言代码
char name[][14]={"B","X","ALL","H","P","B","X","H","P","ALL","B","X","H","P"};//打表输入人 

 由于是14天一个轮回,因此我们可以求出总天数,然后mod14。

然而,每个月的日期又不一样,因此又开始愉快的打表生活

int Month[14]={0,31,28,31,30,31,30,31,31,30,31,30,31,0};//打表输入月份 

假设目标日期为2007年10月20日,通过口算是49天,然后我们很容易想出暴力解法。

int year=2007,month=10,day=20;
int sum=0;
for(int i=9;i<=month;i++){
      sum+=Month[i];
}
sum+=365*(year-2007);
sum+=day-1;

但是如果是2008年呢?2009年呢?(因为i初始为9,如果求的是4月,这样的代码就不行)然后又要去if  else特判,这样未免显得有点复杂。 

因此我们不妨做一个处理,把每个月份的第一天到年末的天数算出来。

int Month[14]={0,31,28,31,30,31,30,31,31,30,31,30,31,0};
int sum=0,month=10,day=20;
//后缀求和,这样Month[i]就表示到年末的天数了
	for(int i=12;i>=1;i--){
		Month[i]+=Month[i+1];
	}
//然后与9月1日的天数差就可以这样表示
    sum=Month[9]-Month[month]+day-1;

看到这里,想必大家会有点蒙。

由于我们做了后缀和处理,实际上现在的Month[9]==30+31+30+31=122,也就是9月1日到年末12月31日的天数了,由于假设的month=10,所以Month[10]=31+30+31=92,也就是10月1日到年末的天数啦。两式相减就是刚好30天,也就是9月的天数,然后我们再加上day的天数-1(减去9月1日)就是总天数49天啦。

然后大家想必还会觉得我这样多此一举,那不妨我们再举个例,2008年2月10日。

还是通过口算得知为162天

int Month[14]={0,31,28,31,30,31,30,31,31,30,31,30,31,0};
int sum=0,year=2008,month=2,day=10;
//后缀求和,这样Month[i]就表示到年末的天数了
	for(int i=12;i>=1;i--){
		Month[i]+=Month[i+1];
	}
//然后与9月1日的天数差就可以这样表示
    sum=Month[9]-Month[month]+day-1;
    sum+=365*(year-2007);

由于后缀和处理,现在的Month[2]即为334了,也就是2月1日到12月31日的天数啦。

带入式子计算sum=365+122-334+10-1=162。计算结果完美符合推测。

综上所述,求和代码即:

sum=365*(year-2007)-Month[month]+Month[9]+day-1;

但是呢,别以为这就完了,题目还有个坑,也就是2008年为闰年!!!2月有29天呢。

通过之前的求和,得知2007年9月1日到2008年2月28日刚好是180天。

因此,当sum>180时,我们让sum++。细心的同学已经发现,这样不就没181了吗?

没错,181即为2月29日,因此我们单独列出来就行。

if(sum>180) sum++;
if(year==2008&&month==2&&day==29) sum=181;

好了,费了这么久的求和总算求完了,接下来就是输出了。

由于之前的规律,我们清楚14天一个轮回,所以只需sum%14就行,也就是输出name[sum%14]。 

最后再将以上散装代码组合即可。

代码实现

c语言

#include<bits/stdc++.h>
int Month[14]={0,31,28,31,30,31,30,31,31,30,31,30,31,0};//打表输入月份 
char name[][14]={"B","X","ALL","H","P","B","X","H","P","ALL","B","X","H","P"};//打表输入人 
int main()
{
    //输入年月日 
    int year,month,day,sum;
	scanf("%d %d %d",&year,&month,&day);
	//后缀和 
	for(int i=12;i>=1;i--){
		Month[i]+=Month[i+1];
	}
	//计算总天数
	sum=365*(year-2007)-Month[month]+Month[9]+day-1;
	if(sum>180) sum++;
	if(year==2008&&month==2&&day==29) sum=181;
    //输出
	printf("%s\n",name[sum%14]);
	return 0;
}

C++

#include<bits/stdc++.h>
using namespace std;
int Month[14]={0,31,28,31,30,31,30,31,31,30,31,30,31,0};//打表输入月份 
string name[14]={"B","X","ALL","H","P","B","X","H","P","ALL","B","X","H","P"};//打表输入人 
int main()
{
    //输入年月日 
    int year,month,day,sum;
	cin>>year>>month>>day;
	//后缀和 
	for(int i=12;i>=1;i--){
		Month[i]+=Month[i+1];
	}
	//计算总天数
	sum=365*(year-2007)-Month[month]+Month[9]+day-1;
	if(sum>180) sum++;
	if(year==2008&&month==2&&day==29) sum=181;
	//输出 
	cout<<name[sum%14]<<endl;
	return 0;
}

 

标签:oj,int,题解,31,30,Month,509,month,sum
来源: https://blog.csdn.net/qq_62102968/article/details/121481475