Educational Codeforces Round 89 D. Two Divisors (数论+gcd性质)

题目链接
题意:
\(n\)个数,对于每个数找到它的两个因子\(d_1、d_2\)使得\(gcd(d_1+d_2,a_i)=1\),若不存在则输出\(-1\)

思路:
由唯一分解定理得:\(a_i={p_1}^{k_1}*{p_2}^{k_2}...{p_m}^{k_m}\)
\(gcd\)性质:\(gcd(a,b)=gcd(a+b,b)\),若\(gcd(a,c)=1\),则\(gcd(a,b)=gcd(a,bc)\)
\(d_1={p_1}^{k_1},d_2={p_2}^{k_2}...{p_m}^{k_m}\),所以\(gcd(d_1,d_2)=1\)
\(gcd(d_1,d_2)=gcd(d_1+d_2,d_1)=gcd(d_1+d_2,d_2)=1\)
\(\Rightarrow\) \(gcd(d_1+d_2,d_1*d_2)=gcd(d_1+d_2,a_i)=1\)
\(a_i\)有两个以上的素数因子时,则必然可以找到\(d_1,d_2\);可以由素数筛\(O(n)\)判断一个数是否为素数且找到其一个素数因子。

  • 素数筛的注意点:
内层循环判断:
for(int j = 1; j <= tot && 1ll * i * p[j] < maxn; j++) {
    // 判断范围时一定是i * p[j] < maxn,而不是p[j] < maxn/i
    // 例如:2 * 4 < 9,但 2 = 9/4
    vis[i * p[j]] = 0;
    if(i % p[j] == 0)break;
}

code:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
const int maxn = 1e7 + 10;

using namespace std;

bool vis[maxn];
int p[maxn], a_p[maxn];
int ans[maxn][2], tot;

void getprime(){
    memset(vis, 1, sizeof vis);
    for(int i = 2; i < maxn; i ++){
        if(vis[i])p[++ tot] = i;
        for(int j = 1; j <= tot && 1ll * i * p[j] < maxn; j ++){
            vis[i * p[j]] = 0;
            a_p[i * p[j]] = p[j];
            if(i % p[j] == 0)break;
        }
    }
}

int main(){
    getprime();
    int n; scanf("%d", &n);
    for(int i = 1, a; i <= n; i++) {
        scanf("%d", &a);
        if(vis[a])ans[i][0] = ans[i][1] = -1;
        else{
            int p = a_p[a], b = 1;
            while(a % p == 0) a /= p, b *= p;
            if(a != 1)ans[i][0] = b, ans[i][1] = a;
            else ans[i][0] = ans[i][1] = -1;
        }
    }
    for(int i = 1; i <= n; i ++)printf("%d ", ans[i][0]); 
    puts("");
    for(int i = 1; i <= n; i++)printf("%d ", ans[i][1]);
    return 0;  
}
posted @ 2021-11-06 00:58  lniiwuw  阅读(87)  评论(0)    收藏  举报