ACM 日常训练
拆根号
毕达哥拉斯定理大家在中学都学过,就是 \(c^{2} = a^{2} + b^{2}\) 。现在让我们来扩展一下,把式子变成 \(\sqrt{c} = \sqrt{a} + \sqrt{b}\),现在告诉你 c 的值,你能解出它的正整数解吗?
Input
第一行输入 t (1 ≤ t ≤ 50) ,接下来有 t 行,表示 t 个不同的 c 值 (1 ≤ c ≤ 8 × 10 \(^{18}\) )。
Output
输出 t 行,每行两个正整数,表示对应的 a 和 b,如果没有正整数解,输出 "no"。如果有多组解,输出任意一个即可。
Sample 1
3
4
6
75
1 1
no
48 3
题解
题目如公式
很明显我们可以构造出一个解:
假设存在质数p使得 c = \(p^{2} * d, d\)为任意一个整数,因此 c = \((p - 1 + 1)^{2} * d\)
所以 a = \((p - 1)^{2} * d, b = d\)。
因此我们只要枚举p是否满足条件
- \((p)^{2}\) | \(c\)
但是直接枚举的话质数要到达\(10^{9}\),所以我们间接枚举。
假设存在一个大质数 \(P^{2}\) 整除 c,并且枚举比 P 小的质数中没有质数满足条件,我们要判断c是否为质数(\(\sqrt{n}\)判断是否为质数),考虑到最坏的情况为 \(p * P^{2} = x\)(p是离P最近的质数),所以我们筛质数到2e6即可。
然后在枚举质数的过程中不同的情况最多不超过10个,所以只有最多有10次进行判断操作,每次判断的时间复杂度为(\(\sqrt{\sqrt{n}}\))。
因此最终的时间复杂度为 $ 50*((1e6以内的质数个数) + 10 * \sqrt{\sqrt{n}}) $。
// 枚举p假如 cnt = 2 即可直接输出求解
int cnt = 0;
while (x % p[i] == 0 && cnt < 2) x /= p[i], cnt++;
// 否则判断一下 c 是不是质数,
c = sqrt((double)x);
if(c * c == x && get(c)){
y /= c * c;
printf("%lld %lld\n", y, y * (c - 1) * (c - 1));
}
#include <iostream>
#include <cstring>
#include <algorithm>
#include <math.h>
using namespace std;
typedef long long ll;
const int N = 2e6 + 5;
int p[N], idx;
bool st[N];
void init(int n){
for (int i = 2; i <= n; i++) {
if (!st[i]) p[idx++] = i;
for (int j = 0; p[j] <= n /i ; j++) {
st[p[j] * i] = true;
if(i % p[j] == 0) break;
}
}
}
bool get(ll x){
if (x <= 1) return false;
for (int i = 2; i <= x / i; i++) {
if (x % i == 0)return false;
}
return true;
}
int main() {
init(N - 1);
int T;
scanf("%d", &T);
while (T--) {
ll x, y;
scanf("%lld", &x);
y = x;
// x = (1e9 + 7);
// x = x * x;
ll c = sqrt((double)x);
if (c * c == x && get(c)){
printf("%lld %lld\n",(c - 1) * (c - 1), 1ll);
}
else {
bool flag = true;
for (int i = 0; i < idx; i++) {
int cnt = 0;
while (x % p[i] == 0 && cnt < 2) x /= p[i], cnt++;
if(cnt == 1){
c = sqrt((double )x);
if(c * c == x && get(c)){
y /= c * c;
printf("%lld %lld\n", y, y * (c - 1) * (c - 1));
flag = false;
break;
}
}
else if(cnt == 2){
c = p[i];
y /= c * c;
printf("%lld %lld\n", y, y * (c - 1) * (c - 1));
flag = false;
break;
}
}
if(flag)puts("no");
}
}
return 0;
}