P8255 [NOI Online 2022 普及组] 数学游戏(民间数据) 题解

原题链接

简要题意:

给定 \(T\)\(x,z\),求 \(\min{y} \space s.t. \space \space x \cdot y \cdot \gcd(x,y) = z\). 可能不存在。

\(T \leq 5 \times 10^5, x \leq 10^9, z < 2^{63}\).

很容易想到从质因数分解的角度入手。

\[\begin{aligned} &xy\gcd(x,y) = z \\ &y\gcd(x,y) = \frac{z}{x} \\ \end{aligned}\]

不妨令对于某个素数 \(p\)\(x\)\(a\) 个,\(y\)\(b\) 个,\(\frac{z}{x}\)\(c\) 个。我们试图已知 \(a,c\) 判断 \(b\). 那么:

\[\begin{aligned} &b + \min(a,b) = c \end{aligned}\]

分类讨论。

对于 \(c > 2a\) 的情况,此时必有 \(b > a\),即 \(b = c - a\).

对于 \(c \leq 2a\) 的情况,此时必有 \(b < a\),即 \(b = \frac{c}{2}\),但存在的条件是 \(c\) 为奇数。

到这里,我们暴力去模拟它,就可以得到一个 \(\mathcal{O}(T\sqrt{z})\) 的做法。但显然这是不优的。

如何快速判断是否存在?可以考虑取 \(r = \min(2a,c)\). 对于 \(c>2a\),一定存在,对应 \(r\) 一定为偶数;对于 \(c \leq 2a\)\(c\) 为偶数时存在,同样对应 \(r\) 为偶数。

也就是说,对于某个素数 \(p\)\(r = \min(2a,c) \equiv 0 \pmod 2\) 则在该素数上存在。

我们再从素因数倒推回去。取所有 \(p^r\) 的乘积,得到的结果就是 \(q = \gcd(x^2, \frac{z}{x})\). 而所有素数的指数为偶数则对应了 \(q\) 为完全平方数。

于是我们已经可以在 \(\mathcal{O}(\log z)\) 的时间内判断无解。

剩下来就很好办了。

\(r = \min(2a, c) = 2a\)\(b = c-a\).

\(r = \min(2a, c) = c\)\(b = \frac{c}{2}\).

考虑用一个式子直接表示 \(b\) 的值。很容易想到:

\[b = c - \frac{\min(2a, c)}{2} \]

这个式子就是本题的真谛所在。由于 \(q\) 是完全平方数,那么此时 \(b\) 一定存在。而将所有 \(p^b\) 乘起来,就是题目所求的答案,整理化简之后也就是

\[y = \frac{\frac{z}{x}}{\sqrt{\gcd(x^2, z)}} \]

时间复杂度:\(\mathcal{O}(T\log z)\).

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

int main() {
	int T; scanf("%d",&T);
	while(T--) {
		ll x, z; scanf("%lld %lld",&x,&z);
		if(z % x) {puts("-1"); continue;}
		z /= x;
		ll p = __gcd(x * x, z);
		ll q = sqrt(p);
		if(q * q == p) printf("%lld\n", z / q);
		else puts("-1");
	}
}
posted @ 2022-03-27 15:30  bifanwen  阅读(144)  评论(0编辑  收藏  举报