1780: LoL?
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 131 Solved: 19
[ Submit][ Status][ Web Board]
Description
Input
Output
Case #x: y,x是测试编号从1开始,y表示答案,如果A最后打死小兵,y为'A',若果同时打死,y为'Both',否则y为'a'
Sample Input
Sample Output
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;
}