专栏文章

题解:P14497 [NCPC 2025] Crochet Competition

P14497题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min7hmvq
此快照首次捕获于
2025/12/01 21:49
3 个月前
此快照最后确认于
2025/12/01 21:49
3 个月前
查看原文

题号:P14497

题目链接:P14497 [NCPC 2025] Crochet Competition

题目简述:

题目给我们两个时间,让我们求出两个时间所差的时间并按要求输出。

思路:

这道题很显然,我们需要模拟计算加特判。具体过程分两步:

第一步,算出时差

两个时间都可以拆成三个部分:星期,时数和分数。
我们先打三个函数用于将字符串分解求时差:
CPP
inline string part_1(string x){
	string z="";
	for(int i=0;i<3;i++) z+=x[i];
	return z;
}//拆出星期
inline int part_2(string x){
	int z=0;
	for(int i=4;i<6;i++) z=z*10+x[i]-'0';
	return z;
}//拆出时数
inline int part_3(string x){
	int z=0;
	for(int i=7;i<9;i++) z=z*10+x[i]-'0';
	return z;
}//拆出分数
可是现在还有一个问题。
我们拆出的第一部分,也就是星期,是一个字符串的形式。我们该如何将字符串转化为数字呢?
没错,用 map 映射可以轻松解决。我们只需要在开始初始化 map 就可以了。
CPP
w["Mon"]=1;w["Tue"]=2;w["Wed"]=3;w["Thu"]=4;w["Fri"]=5;w["Sat"]=6;w["Sun"]=7;
然后我们就可以利用以上代码在后续代码中求出时差了。

第二步,按要求分类讨论输出时差

此题的输出较为繁琐,为了方便,我们写几个便于输出的函数:
CPP
inline void print_1(int x){
	if(x==1) printf("1 day");
	else printf("%d days",x);
}//输出天数
inline void print_2(int x){
	if(x==1) printf("1 hour");
	else printf("%d hours",x);
}//输出时数
inline void print_3(int x){
	if(x==1) printf("1 minute");
	else printf("%d minutes",x);
}//输出分数
我们再来求时差。先将所有时间的单位都化为分钟,再去求时差较为方便:
CPP
int c1=w[part_1(a)]*1440+part_2(a)*60+part_3(a);//起始时间转换
int c2=w[part_1(b)]*1440+part_2(b)*60+part_3(b);//结束时间转换
int c=c2-c1;//求时差
可是如果出现 c1>c2c1 > c2 时,会出现负时差。这个很好解决,特判一下就好了。
CPP
if(c<0) c+=10080;
我选择了最最最复杂的分类讨论。(不到万不得已别学我
首先,我们分类讨论前得求出时差有几个部分。也就是需要输出几个值。可以用简单的运算求出:
CPP
int ans_1=c/1440,ans_2=(c%1440)/60,ans_3=c%60;
//三个值分别为天数,时数和分数。
我们分三类讨论:

第一类,时差共有一个部分

我们找一波哪个是需要输出的值,也就是排除掉 00 后输出就好了。(详见代码)

第二类,时差共有两个部分

我们只需要输出两个值。
找到唯一的 00 后特判输出就好。(详见代码)

第三类,时差共有三个部分

直接照规则输出即可。(详见代码)

注意!

题目中说过:如果开始时间与结束时间完全相同,则比赛时长恰好为一整周。
千万要仔细读题!我就被坑了一回 QWQ。 解决此问题只需一个特判:
CPP
if(s1==s2) printf("7 days");

完整代码:

CPP
#include <bits/stdc++.h>
using namespace std;
map<string,int> w;
string s1,s2;
inline string part_1(string x){
	string z="";
	for(int i=0;i<3;i++) z+=x[i];
	return z;
}
inline int part_2(string x){
	int z=0;
	for(int i=4;i<6;i++) z=z*10+x[i]-'0';
	return z;
}
inline int part_3(string x){
	int z=0;
	for(int i=7;i<9;i++) z=z*10+x[i]-'0';
	return z;
}
inline void print_1(int x){
	if(x==1) printf("1 day");
	else printf("%d days",x);
}
inline void print_2(int x){
	if(x==1) printf("1 hour");
	else printf("%d hours",x);
}
inline void print_3(int x){
	if(x==1) printf("1 minute");
	else printf("%d minutes",x);
}
inline void solve(string a,string b){
	bool f=false;
	if(w[part_1(a)]>w[part_1(b)]||(part_1(a)==part_1(b)&&part_2(a)*60+part_3(a)>part_2(b)*60+part_3(b))) f=true;
	int c1=w[part_1(a)]*1440+part_2(a)*60+part_3(a);
	int c2=w[part_1(b)]*1440+part_2(b)*60+part_3(b);
	if(f) c2+=10080;
	int c=c2-c1;
	int ans_1=c/1440,ans_2=(c%1440)/60,ans_3=c%60;
	if(ans_1==0&&ans_2==0) print_3(ans_3);
	else if(ans_1==0&&ans_3==0) print_2(ans_2);
	else if(ans_2==0&&ans_3==0) print_1(ans_1);
	else if(ans_1==0){
		print_2(ans_2);printf(" and ");print_3(ans_3);
	}
	else if(ans_2==0){
		print_1(ans_1);printf(" and ");print_3(ans_3);
	}
	else if(ans_3==0){
		print_1(ans_1);printf(" and ");print_2(ans_2);
	}
	else{
		print_1(ans_1);printf(", ");print_2(ans_2);printf(", ");print_3(ans_3);
	}
}
int main(){
	w["Mon"]=1;w["Tue"]=2;w["Wed"]=3;w["Thu"]=4;w["Fri"]=5;w["Sat"]=6;w["Sun"]=7;
	getline(cin,s1);
	getline(cin,s2);
	if(s1==s2) printf("7 days");
	else solve(s1,s2);
	return 0;
} //如要注释,可在上文中寻找代码块。

代码总结:

可见我的代码十分复杂,有很多累赘的东西。
可我还是认为,这样写比较方便。
因为这种题细节较多,这样写可以提高正确率。并且在出错时也能对症下药,方便检查。

题目总结:

这道题有许多细节要注意,并没有涉及一些其他的算法。只要基本功扎实,通过本题只是时间问题。可以用来练练手,刷刷手感。

题外话:

以上代码是为了写题解精简后的,我第一次过的代码 190190 多行。(累赘更多
可是写完之后还蛮有成就感的^_^。

评论

0 条评论,欢迎与作者交流。

正在加载评论...