• 2018.9青岛网络预选赛(J)


    传送门:Problem J

    https://www.cnblogs.com/violet-acmer/p/9664805.html

    题目大意:

      BaoBao和DreamGrid玩游戏,轮流按灯的按钮,轮到BaoBao时按下b次,轮到DreamGrid时按下d次,初始时灯是灭的,每次按下按钮等都会持续亮v+0.5秒,如果按之前灯时灭的,则按下后灯会打开,如果灯是亮的,则按下后会从之灯的照明时间为v+0.5,且counter增加1,如果在v+0.5秒每没有再一次按下按钮,灯会熄灭。

      给出a,b,c,d,v,t五个数,t表示游戏时长[0,t],如果当前时刻是a的倍数,则BaoBao按按钮,如果当前时刻是c的倍数,则DreamGrid按按钮,如果是Lcm(a,c)的倍数,则两个人都会按按钮。

    相关变量:

    counter : 计数器

    a,b,c,d,v,t : 题干所给变量

    题解:

      我的想法是先遍历一边a的倍数,再遍历一边c的倍数,两个for( ),第一个for( )中i=a,i每次加a,第二个for( )中i=c,i每次加c。

      ①先除去特殊情况,当v > min(a,c)时,只需在0处将灯打开,之后在灯熄灭前肯定会按下依次min(a,c),在这种情况下灯全程都是亮的。

      ②如果不是特殊情况:通过两个for( )循环每次i += a 或 i += c来减少遍历次数

      第一个循环for(i=a;i <= t;i += a)不考虑在这之前是否有c的影响使当前时刻灯是亮的,所以此时counter += b-1;。

      第二个循环for(i=c;i <= t;i += c)需要考虑第一个循环未考虑的情况,①当前时刻可能受前一个a的影响使灯使亮的,②或受当前时刻的影响,使下一个a时刻灯是亮的。

      如果情况①和情况②同时出现,则在当前时刻不需消耗一次按动使灯打开,但受当前时刻影响,紧接着的a时刻是不需要消耗一次按动打开灯的,但是第一次循环没有考虑这个情况,故counter += d+1;。

      如果情况①和情况②只出现一种,则counter += d;。

      如果都不出现,则counter += d-1;。

    AC代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 using namespace std;
     6 #define esp 1.0e-8
     7 #define INF 10e12+1
     8 typedef long long ll;
     9 
    10 ll counter;
    11 ll a,b,c,d;
    12 ll v,t;
    13 
    14 void Initial()
    15 {
    16     scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
    17     scanf("%lld%lld",&v,&t);
    18     counter=b+d-1;//0时刻的情况
    19 }
    20 bool Special()
    21 {
    22     ll x=(a > c ? c:a);
    23     if(v >= x)
    24     {
    25         counter += (t/a*b+t/c*d);
    26         printf("%lld
    ",counter);
    27         return true;
    28     }
    29     return false;
    30 }
    31 bool is_exit(ll x,ll y,ll num)
    32 {
    33     return x%num == 0 || y%num == 0 || (y/num-x/num > 0);
    34 }
    35 void Process()
    36 {
    37     for(ll time=a;time <= t;time += a)
    38         counter += b-1;
    39         
    40     for(ll time=c;time <= t;time += c)
    41     {
    42         ll suf_time=(time+v <= t ? time+v:t);
    43         bool flag1=is_exit(time-v,time,a);//判断[time-v,time]是否含有a的倍数
    44         bool flag2=is_exit(time,suf_time,a);//判断[time,time+v]是否含有a的倍数
    45         if(time%a == 0)//特判当前时刻是a,c倍数的情况
    46             counter += d;
    47         else if(flag1 && flag2)
    48             counter += d+1;
    49         else if(flag1 || flag2)
    50             counter += d;
    51         else
    52             counter += d-1;
    53     }
    54     printf("%lld
    ",counter);
    55 }
    56 int main()
    57 {
    58     int T;
    59     scanf("%d",&T);
    60     while(T--)
    61     {
    62         Initial();
    63         if(Special())
    64             continue;
    65         Process();
    66     }
    67     return 0;
    68 }
    View Code
  • 相关阅读:
    Lexical Sign Sequence
    (UPCOJ暑期训练)Tally Counters
    (2019hdu多校第十场) Welcome Party
    (2019hdu多校第十场1003) Valentine's Day
    更新,线段树模板(支持相关基本操作)
    linux(deepin)下Clion的安装及环境配置
    2019牛客第7场——C(Governing sand)
    【数论】数论之旅:N!分解素因子及若干问题
    [二分]Kayaking Trip
    [数论之旅]数学定理
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/9667041.html
Copyright © 2020-2023  润新知