-
更新:多谢weixin_44714465同学指出我的错误【详见49-52行代码,已改正!】。CCF CSP的OJ居然没有把这个错误检测出来,不过为了追求严谨,我们还是应该及时改正!
-
题目描述
试题编号: | 201812-2 |
试题名称: | 小明放学 |
时间限制: | 1.0s |
内存限制: | 512.0MB |
问题描述: | 题目背景 汉东省政法大学附属中学所在的光明区最近实施了名为“智慧光明”的智慧城市项目。具体到交通领域,通过“智慧光明”终端,可以看到光明区所有红绿灯此时此刻的状态。小明的学校也安装了“智慧光明”终端,小明想利用这个终端给出的信息,估算自己放学回到家的时间。 问题描述 一次放学的时候,小明已经规划好了自己回家的路线,并且能够预测经过各个路段的时间。同时,小明通过学校里安装的“智慧光明”终端,看到了出发时刻路上经过的所有红绿灯的指示状态。请帮忙计算小明此次回家所需要的时间。 输入格式 输入的第一行包含空格分隔的三个正整数 r、y、g,表示红绿灯的设置。这三个数均不超过 106。 输出格式 输出一个数字,表示此次小明放学回家所用的时间。 样例输入 30 3 30 样例输出 46 样例说明 小明先经过第一段路,用时 10 秒。第一盏红绿灯出发时是红灯,还剩 5 秒;小明到达路口时,这个红绿灯已经变为绿灯,不用等待直接通过。接下来经过第二段路,用时 11 秒。第二盏红绿灯出发时是黄灯,还剩两秒;小明到达路口时,这个红绿灯已经变为红灯,还剩 11 秒。接下来经过第三、第四段路,用时 9 秒。第三盏红绿灯出发时是绿灯,还剩 10 秒;小明到达路口时,这个红绿灯已经变为红灯,还剩两秒。接下来经过最后一段路,用时 3 秒。共计 10+11+11+9+2+3 = 46 秒。 评测用例规模与约定 有些测试点具有特殊的性质: |
-
话不多说,先上代码:
#include<iostream>
#include<cstdio>
using namespace std;
typedef unsigned long long ull;
//题目中有提示,【所有测试点保证 n ≤ 10^5】,题目中可能出现的最大的数为10^6*10^5=10^11,
//int型最大表示的数是2147483647=2*10^9,表示不了,所以需要用大点的类型,如long long 或者是
//unsigned long long。long long最大存储范围是10^18。
int main()
{
ull r, y, g;
ull n;
scanf("%llu%llu%llu%llu", &r, &y, &g, &n);
ull sum = 0;
for(int i = 0; i < n; i++){
ull k, t;
scanf("%llu%llu", &k, &t);
if(k == 0){//遇到的是道路
sum += t;
}else if(k == 1){//遇到红色路灯,等待t秒。注意我们在这里认定信号灯闪烁的顺序为:
//红->绿->黄
if(t >= sum){
sum = t;
}else{
ull temp = 0;
temp = (sum - t + r)%(r + y +g); //假设temp是一个标签,我们通过此标签
//来确定到达红绿灯时刻在【红绿黄周期】的位置,下面同上
if(temp < r+1){//标签落在红灯区间
sum += r - temp;
}else if(temp > r+g){//标签落在黄灯区间
sum += r+g+y - temp+r;//注意,黄灯之后还要等待一个红灯!博主就是在这里被卡住的。
}else {//绿灯不等待
}
}
}else if(k == 2){//遇到黄色路灯,等待t秒。注意我们在这里认定信号灯闪烁的顺序为:
//黄->红->绿
if(t >= sum){
sum = t+r;
}else{
ull temp = 0;
temp = (sum - t + y)%(r + y +g);//假设temp是一个标签,我们通过此标签
//来确定到达红绿灯时刻在【黄红绿周期】的位置,同上
if(temp < y+1){//标签落在黄灯区间
sum += y - temp+r;//注意,黄灯之后还要等待一个红灯!
}else if(temp > r+y){//标签落在绿灯区间
}else {//标签落在红灯区间
sum += r+y - temp;
}
}
}else {//遇到绿色路灯,等待t秒。注意我们在这里认定信号灯闪烁的顺序为:绿->黄->红
//上面第一句话说错了,出发时是绿灯,且到达该信号灯时绿灯的倒计时还未结束,不需要等待t秒!
if(t > sum){
;//不需等待!
}else{
ull temp = 0;
temp = (sum - t + g)%(r + y +g);//假设temp是一个标签,我们通过此标签
//来确定到达红绿灯时刻在【绿黄红周期】的位置,同上
if(temp < g+1){//标签落在绿灯区间
}else if(temp > y+g){//标签落在红灯区间
sum += r+g+y - temp;
}else {//标签落在黄灯区间
sum += g+y-temp+r;//注意,黄灯之后还要等待一个红灯!
}
}
}
}
printf("%llu", sum);
}
-
思路总结:
首先说几个坑:
1.红绿灯的顺序搞清楚。红灯亮了绿灯亮,绿灯亮完后,为了让马路上的车辆尽量开走,又设置了一个黄灯。所以最终顺序为:【。。。】【红灯 绿灯 黄灯】【。。。】
2.数据类型确定好。题目中清楚的描述了【所有测试点保证 n ≤ 10^5】。题目中可能出现的最大的数为10^6*10^5=10^11,int型最大表示的数是2147483647=2*10^9,表示不了,所以需要用大点的类型,如long long 或者是unsigned long long。long long最大存储范围是10^18。
3.明确要求的最终结果:我们需要求的是等待多少时间。
4.unsigned long long 类型的数据,输入输出的占位符是%llu,not %ull!
我的思路:
最开始我的思路十分明确——确定一个标签,想办法计算这个标签到底落到哪个灯所在的区间里。这个思路怎么产生的?可能是与大一刷oj体有关吧,只能是多做题,或者是依靠理解能力分析出来。
第一次结果提交,只得了20分(博主在做练习,正式考试不会提示成绩)。兄弟告诉我过程中用到的数字太大了,让我换一个大类型的数据试试。我恍然大悟,更换成了unsigned long long类型(直接上最大),结果还是得了20分。思考了一天半后,未果。
我决定查看其它博主思路,看了好几篇,只看懂了一篇【CCF CSP 小明放学_Luke技术小站-CSDN博客】。看了这位大佬的思路后,我感觉我的思路没有问题,问题出在了这个点上【当标签落在黄灯区间时,等待的时间为:黄灯的剩余时间 + 等待下一个完整红灯的时间】——我忘记加上【等待下一个完整红灯的时间】了。
提交代码,显示满分。舒服了。
有问题的同学尽量问,能力有限,咱们互相成长!