题目描述
Kri 喜欢玩数字游戏。
一天,他在草稿纸上写下了 t t t对正整数 ( x , y ) (x,y) (x,y),并对于每一对正整数计算出了 z = x ∗ y ∗ g c d ( x , y ) z=x*y*gcd(x,y) z=x∗y∗gcd(x,y)。
可是调皮的Zay找到了Kri的草稿纸,并把每一组的 y y y都擦除了,还可能改动了一些 z z z。
现在Kri想请你帮忙还原每一组的 y y y,具体地,对于每一组中的 x x x和 z z z,你需要输出最小的正整数 y y y,使得 z = x ∗ y ∗ g c d ( x , y ) z=x*y*gcd(x,y) z=x∗y∗gcd(x,y)。如果这样的 y y y不存在,也就是Zay一定改动了 z z z,那么请输出 − 1 -1 −1。
注: g c d ( x , y ) gcd(x,y) gcd(x,y)表示 x x x和 y y y的最大公约数,也就是最大的正整数 d d d,满足 d d d既是 x x x的约数,又是 y y y的约数。
输入格式
第一行一个整数,表示有 t t t对正整数 x x x和 y y y。
接下来 t t t行,每行两个正整数 x x x和 y y y,含义见题目描述。
输出格式
对于每对数字输出一行,如果不存在满足条件的正整数 y y y,请输出 − 1 -1 −1,否则输出满足条件的最小正整数 y y y.
样例
样例输入
3
5 30
4 8
11 11
样例输出
6
-1
1
数据范围
对于 20 % 20\% 20%的数据, t , x , z ≤ 1 0 3 t,x,z\leq10^3 t,x,z≤103。
对于 40 % 40\% 40%的数据, t ≤ 1 0 3 , x ≤ 1 0 6 , z ≤ 1 0 9 t\leq10^3,x\leq10^6,z\leq10^9 t≤103,x≤106,z≤109。
对于另 30 % 30\% 30%的数据, t ≤ 1 0 4 t\leq10^4 t≤104。
对于另 20 % 20\% 20%的数据, x ≤ 1 0 6 x\leq10^6 x≤106。
对于 100 % 100\% 100%的数据, 1 ≤ t ≤ 5 ∗ 1 0 5 , 1 ≤ z ≤ 2 63 1\leq t\leq5*10^5,1\leq z\leq2^{63} 1≤t≤5∗105,1≤z≤263。
分析
首先可以简单地推出
y
∗
g
c
d
(
x
,
y
)
=
z
x
y*gcd(x,y)=\frac{z}{x}
y∗gcd(x,y)=xz,而
z
z
z和
x
x
x是已知变量,所以可以通过枚举
y
y
y或
g
c
d
(
x
,
y
)
gcd(x,y)
gcd(x,y)来判断,肯定是枚举
g
c
d
(
x
,
y
)
gcd(x,y)
gcd(x,y)更快,由于
g
c
d
(
x
,
y
)
gcd(x,y)
gcd(x,y)一定是
x
x
x的因数,于是我们可以枚举
x
x
x的因数来枚举
g
c
d
(
x
,
y
)
gcd(x,y)
gcd(x,y),然后根据推出的式子进一步下推来推出判断式。
y
∗
g
c
d
(
x
,
y
)
=
z
x
y
=
z
x
∗
g
c
d
(
x
,
y
)
g
c
d
(
x
,
z
x
∗
g
c
d
(
x
,
y
)
)
=
j
(
j
即
枚
举
的
x
因
数
)
y*gcd(x,y)=\frac{z}{x}\\ y=\frac{z}{x*gcd(x,y)}\\ gcd(x,\frac{z}{x*gcd(x,y)})=j(j即枚举的x因数)
y∗gcd(x,y)=xzy=x∗gcd(x,y)zgcd(x,x∗gcd(x,y)z)=j(j即枚举的x因数)
这个算法大概是
O
(
t
x
)
O(t\sqrt{x})
O(tx)的时间复杂度,显然不能过,大概能水到40分。
以上是我考试时的思路。
正解如下:
设
d
=
g
c
d
(
x
,
y
)
d=gcd(x,y)
d=gcd(x,y),
x
=
p
∗
d
x=p*d
x=p∗d,
y
=
p
∗
d
y=p*d
y=p∗d,则有
z
=
x
∗
y
∗
d
z
=
p
∗
q
∗
d
3
z
x
=
p
∗
q
∗
d
3
p
∗
d
=
q
∗
d
2
已
知
x
=
p
∗
d
,
z
=
p
∗
q
∗
d
3
,
求
y
y
=
p
d
=
(
p
∗
q
∗
d
3
)
/
(
p
∗
d
)
/
d
即
y
=
z
x
∗
1
d
只
需
求
出
d
即
可
因
为
d
=
g
c
d
(
x
,
y
)
,
所
以
p
与
q
互
质
,
所
以
p
2
与
q
互
质
d
2
=
g
c
d
(
p
2
∗
d
2
,
q
∗
d
2
)
=
g
c
d
(
x
2
,
z
x
)
d
=
g
c
d
(
x
2
,
z
x
)
z=x*y*d\\ z=p*q*d^3\\ \frac{z}{x}=\frac{p*q*d^3}{p*d}=q*d^2\\ 已知x=p*d,z=p*q*d^3,求y\\ y=pd=(p*q*d^3)/(p*d)/d\\ 即y=\frac{z}{x}*\frac{1}{d}\\ 只需求出d即可\\ 因为d=gcd(x,y),所以p与q互质,所以p^2与q互质\\ d^2=gcd(p^2*d^2,q*d^2)=gcd(x^2,\frac{z}{x})\\ d=\sqrt{gcd(x^2,\frac{z}{x})}
z=x∗y∗dz=p∗q∗d3xz=p∗dp∗q∗d3=q∗d2已知x=p∗d,z=p∗q∗d3,求yy=pd=(p∗q∗d3)/(p∗d)/d即y=xz∗d1只需求出d即可因为d=gcd(x,y),所以p与q互质,所以p2与q互质d2=gcd(p2∗d2,q∗d2)=gcd(x2,xz)d=gcd(x2,xz)
你以为已经完了吗?
不!
不然它给你-1干嘛
所以,我们还需要判断是否合法。
分析一下,以上方法是否有漏洞。
很明显,真相只有一——
啊不,两个。
首先,
g
c
d
(
x
2
,
z
x
)
\sqrt{gcd(x^2,\frac{z}{x})}
gcd(x2,xz)的这个根号
很不行!
根号下的数不一定能开出整数,于是就会出现这样的情况:
我们算出的
d
′
=
g
c
d
(
x
2
,
z
x
)
=
⌊
g
c
d
(
x
2
,
z
x
)
⌋
d'=\sqrt{gcd(x^2,\frac{z}{x})}=\lfloor\sqrt{gcd(x^2,\frac{z}{x})}\rfloor
d′=gcd(x2,xz)=⌊gcd(x2,xz)⌋
而真正的
d
=
g
c
d
(
x
2
,
z
x
)
d=\sqrt{gcd(x^2,\frac{z}{x})}
d=gcd(x2,xz)
所以
d
′
≠
d
d'\neq d
d′=d
所以只有当算出来的
d
′
d'
d′等于真正的
d
d
d时,才有答案。
而当真正的
d
d
d等于
d
′
d'
d′的时候,
d
=
g
c
d
(
x
,
y
)
=
g
c
d
(
x
,
z
/
x
/
d
′
)
d=gcd(x,y)=gcd(x,z/x/d')
d=gcd(x,y)=gcd(x,z/x/d′)
所以判断条件就应该是
⌊
d
′
⌋
\lfloor d'\rfloor
⌊d′⌋是否等于
d
′
d'
d′
其次
谁说
z
z
z一定整除
x
x
x了?
第二个条件就显而易见了:
当
z
%
x
=
=
0
z\%x==0
z%x==0时,输出
−
1
-1
−1.
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL t,x,z;
LL gcd(LL aa,LL bb) {
if(!bb) return aa;
return gcd(bb,aa%bb);
}
int main() {
scanf("%lld",&t);
for(int i=1;i<=t;i++) {
scanf("%lld%lld",&x,&z);
if(z%x!=0) {
printf("-1\n");
continue;
}
double d=sqrt(gcd(x*x,z/x)*1.0);
if(floor(d)==d) printf("%lld\n",z/x/(long long)d);
else printf("-1\n");
}
return 0;
}
官方数据竟然比民间数据还水???