当前位置: 代码迷 >> 综合 >> swust oj 题解#509 寝室扫地问题
  详细解决方案

swust oj 题解#509 寝室扫地问题

热度:76   发布时间:2023-12-05 17:47:04.0

目录

题目

思路解析

代码实现


题目

思路解析

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

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

Mon Tue Wed Thu Fri Sat Sun
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) 13 14
15(ALL) 16 17 18 19 20 21
22 23 24 25 26 27

28

29 30 31
11月 1 2 3 4

想必根据表格,已经找出规律了吧,也就是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;
}