CF1451D Circle Game 题解
给出一个半径为 $d$ 的圆,以 $(0,0)$ 为起点,每次可以向上或向右移动 $k$ 个单位,先移出圆的为败,求先手还是后手能赢。
思路分析
经过分析可以发现,无论对方怎么走,先手可以保证在直线 $y=x+k$ 或 $y=x-k$ 上行走,后手可以保证在直线 $y=x$ 上行走。因此,当存在一个必胜点(即下一步必定出圆) $(x,y)$ 满足 $|y-x|=k$ 且 $k|x$ ,则先手可以走到这里保证必胜;同理,当存在一个必胜点 $(x,y)$ 满足 $x=y$ 且 $k|x$ ,则后手可以走到这里保证必胜。
具体实现
显然我们应该首先在直线 $y=x$ 上走得尽量远,然后判断最远的点是否为必胜点,如果是则后手胜,否则先手胜。具体判断即看下一步是否会超出圆。显然最远即半径长 $d$ ,而每走 $2$ 步走的距离即为 $\sqrt{2}k$ ,因此能走的最大步数为 $2\left \lfloor \frac{d}{\sqrt{2}k} \right \rfloor$ ,此时的坐标为 $(k\left \lfloor \frac{d}{\sqrt{2}k} \right \rfloor,k\left \lfloor \frac{d}{\sqrt{2}k} \right \rfloor)$ 。下一步往上走和往右走都一样,即走到 $(k\left \lfloor \frac{d}{\sqrt{2}k} \right \rfloor,k(\left \lfloor \frac{d}{\sqrt{2}k} \right \rfloor+1))$ ,用两点间的距离公式判断是否出圆即可,即最终只需要判断 $(k\left \lfloor \frac{d}{\sqrt{2}k} \right \rfloor)^2+(k(\left \lfloor \frac{d}{\sqrt{2}k} \right \rfloor+1))^2>d^2$ ,若成立,则会超出,后手胜;否则先手胜。向下取整可以直接强制类型转换为整型。
#include<iostream>
#include<cstdio>
#include<cmath>
#define ll long long
#define ld long double
using namespace std;
int T;
ll d,k;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld",&d,&k);
puts(pow(k*(ll)((ld)d/sqrt((ld)2)/k),2)+pow(k*(ll)((ld)d/sqrt((ld)2)/k+1),2)>d*d?"Utkarsh":"Ashish");
}
return 0;
}