CCF CSP 201812-2 小明放学 解题思路及经验总结

  • 更新:多谢weixin_44714465同学指出我的错误【详见49-52行代码,已改正!】。CCF CSP的OJ居然没有把这个错误检测出来,不顾为了追求严谨,我们还是应该及时改正!

  • 题目描述

试题编号: 201812-2
试题名称: 小明放学
时间限制: 1.0s
内存限制: 512.0MB
问题描述:

题目背景

  汉东省政法大学附属中学所在的光明区最近实施了名为“智慧光明”的智慧城市项目。具体到交通领域,通过“智慧光明”终端,可以看到光明区所有红绿灯此时此刻的状态。小明的学校也安装了“智慧光明”终端,小明想利用这个终端给出的信息,估算自己放学回到家的时间。

问题描述

  一次放学的时候,小明已经规划好了自己回家的路线,并且能够预测经过各个路段的时间。同时,小明通过学校里安装的“智慧光明”终端,看到了出发时刻路上经过的所有红绿灯的指示状态。请帮忙计算小明此次回家所需要的时间。

输入格式

  输入的第一行包含空格分隔的三个正整数 r、y、g,表示红绿灯的设置。这三个数均不超过 106。
  输入的第二行包含一个正整数 n,表示小明总共经过的道路段数和路过的红绿灯数目。
  接下来的 n 行,每行包含空格分隔的两个整数 k、t。k=0 表示经过了一段道路,将会耗时 t 秒,此处 t 不超过 106;k=1、2、3 时,分别表示出发时刻,此处的红绿灯状态是红灯、黄灯、绿灯,且倒计时显示牌上显示的数字是 t,此处 t 分别不会超过 r、y、g。

输出格式

  输出一个数字,表示此次小明放学回家所用的时间。

样例输入

30 3 30
8
0 10
1 5
0 11
2 2
0 6
0 3
3 10
0 3

样例输出

46

样例说明

  小明先经过第一段路,用时 10 秒。第一盏红绿灯出发时是红灯,还剩 5 秒;小明到达路口时,这个红绿灯已经变为绿灯,不用等待直接通过。接下来经过第二段路,用时 11 秒。第二盏红绿灯出发时是黄灯,还剩两秒;小明到达路口时,这个红绿灯已经变为红灯,还剩 11 秒。接下来经过第三、第四段路,用时 9 秒。第三盏红绿灯出发时是绿灯,还剩 10 秒;小明到达路口时,这个红绿灯已经变为红灯,还剩两秒。接下来经过最后一段路,用时 3 秒。共计 10+11+11+9+2+3 = 46 秒。

评测用例规模与约定

  有些测试点具有特殊的性质:
  * 前 2 个测试点中不存在任何信号灯。
  测试点的输入数据规模:
  * 前 6 个测试点保证 n ≤ 103。
  * 所有测试点保证 n ≤ 105。

  • 话不多说,先上代码:

#include
#include
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分。思考了一天半后,未果。

    我决定查看其它博主思路,看了好几篇,只看懂了一篇【https://blog.csdn.net/happywlg123/article/details/87864575】。看了这位大佬的思路后,我感觉我的思路没有问题,问题出在了这个点上【当标签落在黄灯区间时,等待的时间为:黄灯的剩余时间 + 等待下一个完整红灯的时间】——我忘记加上【等待下一个完整红灯的时间】了。

    提交代码,显示满分。舒服了。

    有问题的同学尽量问,能力有限,咱们互相成长!

你可能感兴趣的:(CCF,CSP,C++)