ccf 201812-2

题目背景
  汉东省政法大学附属中学所在的光明区最近实施了名为“智慧光明”的智慧城市项目。具体到交通领域,通过“智慧光明”终端,可以看到光明区所有红绿灯此时此刻的状态。小明的学校也安装了“智慧光明”终端,小明想利用这个终端给出的信息,估算自己放学回到家的时间。
问题描述
  一次放学的时候,小明已经规划好了自己回家的路线,并且能够预测经过各个路段的时间。同时,小明通过学校里安装的“智慧光明”终端,看到了 出发时刻路上经过的所有红绿灯的指示状态。请帮忙计算小明此次回家所需要的时间。
 
输入格式
  输入的第一行包含空格分隔的三个正整数 r、y、g,表示红绿灯的设置。这三个数均不超过 10 6
  输入的第二行包含一个正整数 n,表示小明总共经过的道路段数和路过的红绿灯数目。
  接下来的 n 行,每行包含空格分隔的两个整数 k、t。k=0 表示经过了一段道路,将会耗时 t 秒,此处 t 不超过 10 6;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 ≤ 10 3
  * 所有测试点保证 n ≤ 10 5
 
 
80分代码:一个一个推,超时
 
#include <stdio.h>

using namespace std;

int now_k, now_t;
int light[3];        //0是红灯  1是绿灯  2是黄灯 

void Count(long long time, int k, int t){
    if(k==0){
        now_k=k;
        now_t=t;
        return;
    }
    if(t-time>0){
        now_k=k;
        now_t=t-time;
        return;
    }
    int start;
    time-=t;        //剔除掉多余的部分,往后移一格,从下一格开始计算 
    if(k==1)    start=1;        //红灯变成绿灯 
    else if(k==2)    start=0;    //黄灯变成红灯 
    else    start=2;            //绿灯变成黄灯 
    while(1){
        if(time<light[start]){
            now_t=light[start]-time;
            if(start==0)    now_k=1;
            else if(start==1)    now_k=3;
            else    now_k=2;
            return;
        }
        else{
            time-=light[start];
            if(start==2)    start=0;    //当前是最后一块,则返回到第一块 
            else start++;                //否则++ 
        }
    }     
}
 
    //k=1红灯  k=2黄灯  k=3绿灯
                                    
int main(){                    //红 绿 黄 
    int red,yellow,green;
    int n,k,t;
    long long time;
    while(scanf("%d %d %d",&red,&yellow,&green)!=EOF){
        scanf("%d",&n);
        time=0;
        light[0]=red;    light[1]=green;        light[2]=yellow; 
        for(int i=0;i<n;i++){
            scanf("%d %d",&k,&t);
            if(i==0){                //开始的时候直接计算 
                if(k==0)    time+=t;
                else if(k==1)    time+=t;
                else if(k==2)    time+=t+red;
            }
            else{
                Count(time,k,t);
                if(now_k==0)    time+=now_t;
                else if(now_k==1)    time+=now_t;
                else if(now_k==2)    time+=now_t+red;
                
            }        
        }
        printf("%lld\n",time);
    }
    return 0;
}

题解:

①用一个light[3]数组记录红绿黄灯的时间,注意下标和k值的对应。

②用当前以及经过的时间和初始状态下红绿灯的颜色和剩余时间,推出现在时刻的红绿灯的颜色及剩余时间

③用long long sum = red+yellow+green 来记录一个红绿灯的周期,time包含n个周期,而我们只需要知道最后一个周期即可,前面n-1个周期是没有用的。所以不用一个一个往后推,直接求余周期,得到最后一个周期即可。如果当前经过的时间不足一个周期也不会出错,因为小的数模大的数得到的结果是小的数本身,比如2%5=2。

用当前时间time%sum=r,得到最后一个周期的时间,再用最后一个周期的时间来计算当前红绿灯的颜色和剩余时间即可(不要一个一个往后推,会超时的!www)

#include <stdio.h>

using namespace std;

int now_k, now_t;
int light[3];        //0是红灯  1是绿灯  2是黄灯 
long long sum;    //一个红绿灯的周期

void Count(long long time, int k, int t){
    if(k==0){
        now_k=k;
        now_t=t;
        return;
    }
    if(t-time>0){
        now_k=k;
        now_t=t-time;
        return;
    }
    int start;
    time-=t;        //剔除掉多余的部分,往后移一格,从下一格开始计算周期 
    int r =time%sum;        //计算最后一个周期            //小的数模大的数等于小的数本身
    if(k==1)    start=1;        //红灯变成绿灯 
    else if(k==2)    start=0;    //黄灯变成红灯 
    else    start=2;            //绿灯变成黄灯 
    while(1){
        if(r<light[start]){
            now_t=light[start]-r;
            if(start==0)    now_k=1;
            else if(start==1)    now_k=3;
            else    now_k=2;
            return;
        }
        else{
            r-=light[start];
            if(start==2)    start=0;    //当前是最后一块,则返回到第一块 
            else start++;                //否则++ 
        }
    }     
}
 
//k=1红灯  k=2黄灯  k=3绿灯
                                    
int main(){                    //亮灯顺序:红 绿 黄 
    int red,yellow,green;
    int n,k,t;
    long long time;
    while(scanf("%d %d %d",&red,&yellow,&green)!=EOF){
        scanf("%d",&n);
        time=0;        sum=0;
        sum = red+yellow+green;        //一个红绿灯周期 
        light[0]=red;    light[1]=green;        light[2]=yellow; 
        for(int i=0;i<n;i++){
            scanf("%d %d",&k,&t);
            if(i==0){                //开始的时候直接计算 
                if(k==0)    time+=t;
                else if(k==1)    time+=t;
                else if(k==2)    time+=t+red;
            }
            else{
                Count(time,k,t);
                if(now_k==0)    time+=now_t;
                else if(now_k==1)    time+=now_t;
                else if(now_k==2)    time+=now_t+red;    
            }        
        }
        printf("%lld\n",time);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/shiliuxinya/p/12192302.html