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;
}
posted @ 2022-05-07 23:39  什么都不会的娃娃  阅读(105)  评论(0)    收藏  举报