【题解】NOI Online 2022 数学游戏题解

本文探讨了一道编程题,涉及数字游戏和最大公约数。题目要求根据x和z还原y的值,即找到最小的y使得z = x * y * gcd(x, y)成立。通过分析,得出y = z / (x * gcd(x, y)),并通过枚举gcd(x, y)来求解。但实际解题过程中需要注意,gcd(x^2, z / x)可能无法开平方根为整数,以及z不一定整除x。代码实现中需判断这两个条件,否则输出-1表示无解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目(luogu)

题目描述

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=xygcd(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=xygcd(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,z103
对于 40 % 40\% 40%的数据, t ≤ 1 0 3 , x ≤ 1 0 6 , z ≤ 1 0 9 t\leq10^3,x\leq10^6,z\leq10^9 t103,x106,z109
对于另 30 % 30\% 30%的数据, t ≤ 1 0 4 t\leq10^4 t104
对于另 20 % 20\% 20%的数据, x ≤ 1 0 6 x\leq10^6 x106
对于 100 % 100\% 100%的数据, 1 ≤ t ≤ 5 ∗ 1 0 5 , 1 ≤ z ≤ 2 63 1\leq t\leq5*10^5,1\leq z\leq2^{63} 1t5105,1z263

分析

首先可以简单地推出 y ∗ g c d ( x , y ) = z x y*gcd(x,y)=\frac{z}{x} ygcd(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因数) ygcd(x,y)=xzy=xgcd(x,y)zgcd(x,xgcd(x,y)z)=j(jx)
这个算法大概是 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=pd y = p ∗ d y=p*d y=pd,则有
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=xydz=pqd3xz=pdpqd3=qd2x=pd,z=pqd3,yy=pd=(pqd3)/(pd)/dy=xzd1dd=gcd(x,y),pq,p2qd2=gcd(p2d2,qd2)=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;
}

官方数据竟然比民间数据还水???

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值