1. 程式人生 > 其它 >P8255 [NOI Online 2022 普及組] 數學遊戲(民間資料) 題解

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");
	}
}