[NOI online2022普及B] 数学游戏
题目描述
Kri 喜欢玩数字游戏。
一天,他在草稿纸上写下了 \(t\) 对正整数 \((x,y)\),并对于每一对正整数计算出了 \(z=x\times y\times\gcd(x,y)\)。
可是调皮的 Zay 找到了 Kri 的草稿纸,并把每一组的 \(y\) 都擦除了,还可能改动了一些 \(z\)。
现在 Kri 想请你帮忙还原每一组的 \(y\),具体地,对于每一组中的 \(x\) 和 \(z\),你需要输出最小的正整数 \(y\),使得 \(z=x\times y\times\gcd(x,y)\)。如果这样的 yy 不存在,也就是 Zay 一定改动了 \(z\),那么请输出 \(-1\)。
注:\(\gcd(x,y)\) 表示 xx 和 yy 的最大公约数,也就是最大的正整数 \(d\),满足 \(d\) 既是 \(x\) 的约数,又是 \(y\) 的约数。
输入格式
第一行一个整数 ,表示有 \(t\) 对正整数 \(x\) 和 \(z\)。
接下来 tt 行,每行两个正整数 \(x\) 和 \(z\),含义见题目描述。
输出格式
对于每对数字输出一行,如果不存在满足条件的正整数 \(y\),请输出 \(-1\),否则输出满足条件的最小正整数 \(y\)。
输入输出样例
输入 #1
1
10 240
输出 #1
12
输入 #2
3
5 30
4 8
11 11
输出 #2
6
-1
1
输入 #3复制
见附件中的 math3.in
输出 #3复制
见附件中的 math3.out
输入 #4复制
见附件中的 math4.in
输出 #4复制
见附件中的 math4.out
说明/提示
【样例 1 解释】
\(x\times y\times \gcd(x,y)=10\times 12\times\gcd(10,12)=240\)
【数据范围】
对于 \(20\%\) 的数据,\(t, x, z \le {10}^3\)
对于 \(40\%\) 的数据,\(t \le {10}^3\),\(x \le {10}^6\),\(z \le {10}^9\)。
对于另 \(30\%\) 的数据,\(t \le {10}^4\)
对于另 \(20\%\) 的数据,\(x \le {10}^6\)。
对于 \(100\%\) 的数据,\(1 \le t \le 5 \times {10}^5\),\(1 \le x \le {10}^9\) ,\(1 \le z < 2^{63}\) 。
设\(\gcd(x,y)\)为\(d\),\(x=ad\),\(y=bd\),\(z=abd^3\)
尝试解出\(d\),现在\(z\)中去掉\(a\),\(z\div x =bd^2\)
利用上\(\gcd(a,b)=1\),\(\gcd(x^2,z\div x)\)就是\(d^2\),开个根就能得到\(d\)。
然后用\(z\div x\div d\)就是\(bd\),也就是\(y\)。然后在开根或很多地方可能会出现问题,所以把\(y\)带入式子验证一下。
#include<cstdio>
#include<cmath>
int t,x;
long long z,y,d;
long long gcd(long long x,long long y)
{
if(x<y)
return gcd(y,x);
if(!y)
return x;
return gcd(y,x%y);
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%lld",&x,&z);
y=z/x;
d=sqrt(gcd(1LL*x*x,y));
y=y/d;
if(x*y*gcd(x,y)!=z)
printf("-1\n");
else
printf("%lld\n",y);
}
}