此题和"小明上学"题干类似,不过我们需要模拟时间的流动来预测小明到达红绿灯时红绿灯的状态。
这里我们增加了一个eclipse()函数来实现,实际上类似于状态机。
思路详解
把红绿灯的状态看成是<颜色k,剩余秒数t>,经过的时间是各个状态之间的转化边,那么我们可以描述一下红绿灯的有限状态机:
初始状态为<红灯,30秒>,经过30秒后状态将变成<绿灯,g秒>,其中g是绿灯的总时长;
再经过g秒,状态将变为<黄灯,y秒> ;
此时如果经过了5秒,而5秒不足以让黄灯变成红灯,即5<y,那么状态将变为<黄灯,(y-5)秒>;
本题中我们已知红绿灯的初始状态和经过的秒数, 只要根据状态机一步一步推理,则我们能够得到最后的状态<k, t>.
C++11满分代码
#include <iostream>
using namespace std;
int k, t;
long long total = 0; // 当n=10^5时,结果的数量级可能会达到10^5*10^6
int r, y, g, n;
/* 模拟时间的流动 */
void eclipse()
{
int clock = total % (r + y + g); // 优化:因为ryg是一个周期,因此条目状态是一样的
while (true)
{
if (clock < t)
{
t -= clock;
break;
}
if (k == 1) // red
{
clock -= t;
k = 3;
t = g;
}
else if (k == 2) // yellow
{
clock -= t;
k = 1;
t = r;
}
else if (k == 3) // green
{
clock -= t;
k = 2;
t = y;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> r >> y >> g >> n;
while (n--)
{
cin >> k >> t;
if (k != 0)
eclipse();
// 下面是"小明上学"的代码
switch (k)
{
case 0:
case 1:
total += t;
break;
case 2:
total += t + r;
break;
default:
break;
}
}
cout << total;
return 0;
}