ZCMU-校赛E-1780

1780: LoL?

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 131   Solved: 19
[ Submit][ Status][ Web Board]

Description

校园的生活是美好的,学习之余,大家都有着自己的休闲方式,听音乐,看电影,打游戏什么的,说到游戏,不得不说一个很有意思的游戏,这个游戏中需要两位同志配合一起,开始的时候只能靠攻击小兵挣钱,挣钱的规则是谁最后打死这个小兵那么谁就可以获得25块钱....,某日,一对基佬A,a玩起了这个游戏,现在知道A的攻击速度是每一秒可以攻击小兵n下,a的攻击速度是每一秒可以攻击小兵m下,现在二人都做好了攻击准备,那么最后小兵会是谁打死的?

Input

第一行T(T<=100000),第二行n,m,x(n,m<=10^6)。n表示A的攻速,m表示a的攻速,x(x<=10^9)表示小兵血量(a,A每攻击小兵一次,小兵扣除1滴血

Output

Case #x: y,x是测试编号从1开始,y表示答案,如果A最后打死小兵,y为'A',若果同时打死,y为'Both',否则y为'a'

Sample Input

4
3 2 1
3 2 2
3 2 3
3 2 4

Sample Output

Case #1: A
Case #2: a
Case #3: A
Case #4: Both

HINT



样例1,小兵血量是1,A在1/3秒攻击小兵,所以A击杀小兵,样例4,1/3秒A攻击小兵,1/2秒a攻击,2/3秒A攻击,2/2,3/3是二者同时攻击


【解析】

恩,这道题看了大佬的算法,感觉还是二分查找和之前的有道题类似都是会二分,忽然发现二分会用的话貌似都用的到,这里我就用大佬的算法来解释了,意思是这样子的,攻速是整数不过扣血显然比如你1/3是0.33333这样的话不好做,因为小数来判断哪个先打死肯定比整数来的难,所以我们这里就把1s放大,我们把1s放大之后,当然放大多少倍由两个攻速的最小公倍数决定这样会比较好算。有个优化是前面多少秒的掉血我们

就不管它了,我们只考虑它被打死的那一秒就好了。就用a%b,a是代表多少血量,而b代表的是在一秒当中扣多少血其实也就是n+m,这样的话,我们只用考虑他快被打死的那一秒,其实取余既然有余数那肯定是你b小的,所以你怪肯定是在那一秒被打死的。问题来了,你把时间放大之后攻速为3的他攻击三次,但是在什么时候攻击呢?比如你分为1,2,3,4,5,6那么在A攻击的时候就是在2,4,6,的时候攻击,也就是说他是在

6/3为2的倍数的时候攻击的,其实每一个位置所扣的血量是i/n+i/m的大家可以算一下,在i为1的时候不扣血,为2的时候扣一滴这时候我们会发现越往后面扣血扣的越多,那么我们怎么算他正好扣完血呢,二分查找了,如果扣的血比它剩下的血多,我们就要往前面找,如果扣的血比它剩下的血少,我们就往后查找,因为后面扣得血多。还有一点就是如果在一个时间点内是两人同时攻击的其实他只剩下一滴血的那么只扣一滴血。所以这里其实就是二分查找法。

#include<cstdio>
#include<iostream>
using namespace std;
int gcd(int a,int b)
{
    int tmp;
    while(b!=0)
    {
        tmp=a%b;
        a=b;
        b=tmp;
    }
    return a;
}
int main()
{
    int t,i,j;
    long long n,m,x,p,q,k,count1=0,left,right,mid,w,u,b;
    scanf("%d",&t);
    while(t--)
    {
        count1++;
        scanf("%lld%lld%lld",&n,&m,&x);
        x=x%(n+m);
        if(x==0)
            {
                printf("Case #%d: Both\n",count1);
                continue;
            }
        p=n;
        q=m;
        u=n;
        b=m;
        k=gcd(p,q);
        n=((u*b)/k)/n;
        m=((u*b)/k)/m;
        left=0;
        right=((u*b)/k);
        while(left<=right)
        {

            mid=(left+right)/2;
            w=mid/n+mid/m;//扣多少血
            if((w==x+1)&&(mid%n==0)&&(mid%m==0))//这样的话就是说明在那一秒双方同时打的
            {
                printf("Case #%d: Both\n",count1);
                break;
            }
            if(x==w)
            {
                if(mid%n==0&&mid%m==0)
                {
                     printf("Case #%d: Both\n",count1);
                            break;
                }
            if(mid%n==0)
            {
                printf("Case #%d: A\n",count1);//此时拿3,2,1举例子,此时n为2,他的攻速是3这个时候取余数成功代表他终结了BOSS
                break;
            }
            if(mid%m==0)
            {
                printf("Case #%d: a\n",count1);
                break;
            }
            right=mid-1;//这里表示虽然扣得血和剩下的血一样多但是在那个时候没有人打,所以肯定是在前面
            //因为在mid那个位置你扣得血是和剩下的是一样的但是不可能正在在那个时间打完因为mid%m或者n都不是0
            //那么就是只有一种可能是在mid前面的不然扣得血一定比剩下的血少
            }
            else
            {
            if(w>x)
                right=mid-1;
            else if(w<x)
                left=mid+1;
            }
        }

    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值