问题描述

试题编号:

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。

 

问题解析:

        本题跟第一题的解题思路是大致相同的。每输入一组k和t,即经过一个路口或红绿灯,都计算我需要在这里花费多长时间。第一题比较简单,当下花费的时间与之前所花费的时间无关,所以可以直接将花费的时间简单地累加起来。但是第二题就比较复杂,当下经过某个地方所需要花费的时间与之前花费了的时间有关,我们需要找到这层关系。本题中有一个关系要搞明白,就是红绿黄灯上所显示的时间是当前状态还剩多久,而并不是这个状态已经持续了多久,也就是说,一个红灯所持续了的时间应该是红灯总时间减掉显示的时间。

解题思路:

        本题是要找当前经过一个地方所花费的时间与之前花费的时间之间的关系。我从第一题中得到了灵感,第一题中说:从 0 时刻起,[0,r) 秒内亮红灯,车辆不许通过;[r, r+g) 秒内亮绿灯,车辆允许通过;[r+g, r+g+y) 秒内亮黄灯,车辆不许通过,然后依次循环。根据这段话,我们知道红绿灯的循环过程是:红—绿—黄—红—绿—黄—红······所以我们就把一次红—绿—黄当做一个周期,红灯持续了0秒为周期的初始状态。对每一组输入都计算这个灯从初始状态到小明到达这个灯所花费的时间。而这个时间,一定要从初始状态开始计算,这是为了对周期时间取余,然后得到它此刻的状态。

        例如:红灯15秒,绿灯20秒,黄灯10秒。在我们出发时有一个灯,是还剩10秒的红灯,在经过一段50秒的平路后到达这个红灯。首先,根据我上面定义的周期,这个红灯已经持续了15-10=5秒,然后50秒后到达这个红灯,此时这个灯已经花费了50+5=55秒。那么这个55就是从初始状态到小明到达这个灯时它所花费的时间,现在要确定这个灯的状态和所剩时间,用55取余一个周期的时间,即55%(15+20+10)=10。即到达这个灯时它的状态是还剩15-10=5秒的红灯。

        最后理一下思路,对于每组输入的k和t,如果k=0,那么直接将t累加,res+=t。如果k=1,2,3,先计算从初始状态到当前状态所花费的时间,再加上前面所花费的时间res,就是从初始状态到小明到达这个灯时花费的时间。将这个时间与周期时间取余,根据余数来确定到达这个灯时它的状态。

代码及细节:

        本题有一个坑就是结果会超过int的范围,我们需要将变量设置为long long类型。其中,res为结果,一定要设为long long型。坑就在于程序中输入的变量 t ,它要加上前面所花费的时间res,所以这个变量也可能越界,也要设成long long型,考试的时候没注意这点,结果才60分。。。

#include<iostream>
using namespace std;
int main()
{
	long long res=0,t;
	int r,y,g,n,k;
	cin>>r>>y>>g>>n;
	while(n--)
	{
		cin>>k>>t;
		switch(k)
		{
			//平路的话直接加上花费的时间 
			case 0:{
				res+=t;
				break;
			}
			//红灯的话,从初始状态到当前状态所花费的时间是r-t,然后加上res,再对(r+g+y)取余。 
			case 1:{
				t=(r-t)+res;
				t%=(r+g+y);
				if(t<r)		//若持续时间小于红灯总时间,那么经过这个灯的时间就是红灯所剩的时间。 
					res+=(r-t);		 
				else if(t>=g+r)		//若持续时间大于红+绿总时间且小于黄灯总时间,即在黄灯状态下,就既要等黄灯还要等红灯。 
					res+=(r+r+g+y-t);		//r+g+y-t是当前黄灯所剩的时间。 
				break;
			}
			//黄灯的话,从初始状态到当前状态所花费的时间是r+g+y-t,然后加上res,再对(r+g+y)取余。 
			case 2:{
				t=(r+g+y-t)+res;
				t%=(r+g+y);
				if(t<r)
					res+=(r-t);
				else if(t>=g+r)
					res+=r+(r+g+y-t);
				break;
			}
			//绿灯的话,从初始状态到当前状态所花费的时间是r+g-t,然后加上res,再对(r+g+y)取余。 
			case 3:{
				t=(r+g-t)+res;
				t%=(r+g+y);
				if(t<r)
					res+=(r-t);
				else if(t>=g+r)
					res+=r+(r+g+y-t);
				break;
			}
		}
	}
	printf("%lld",res);
	return 0; 
}