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
原文地址:https://www.cnblogs.com/violet-acmer/p/9667041.html