swust oj 题解#509 寝室扫地问题(保姆级教学)
作者:互联网
目录
题目
思路解析
按照这个题的思路,我们不妨做一个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;
}
标签:oj,int,题解,31,30,Month,509,month,sum 来源: https://blog.csdn.net/qq_62102968/article/details/121481475