为美好的XCPC线上典题——EDU89 D. Two Divisors(数论)

题意

给定 nnn 个整数 a1,a2,…,ana_1, a_2, \dots, a_na1,a2,,an

对于每个 aia_iai ,找出它的两个因数 d1>1d_1 > 1d1>1d2>1d_2 > 1d2>1 ,使得 gcd⁡(d1+d2,ai)=1\gcd(d_1 + d_2, a_i) = 1gcd(d1+d2,ai)=1 (其中 gcd⁡(a,b)\gcd(a, b)gcd(a,b)aaabbb 的最大公约数),或者说不存在这样的对。

给定 nnn 个整数 a1,a2,…,ana_1, a_2, \dots, a_na1,a2,,an 。对于每个 aia_iai 找到它的两个因数d1>1d_1 > 1d1>1d2>1d_2 > 1d2>1 使得 gcd(d1+d2,ai)=1gcd(d_1 + d_2, a_i) = 1gcd(d1+d2,ai)=1 (其中 gcd(a,b)gcd(a, b)gcd(a,b)aaabbb 的最大公约数)或说不存在这样的对。

思路

一般涉及到因数的题目都应该联想到将其质因数分解,此题也不例外

为了方便下文用nnn替代aia_iai

我们令n=p1k1∗p2k2∗…pmkm=∏pikin = p_1^{k_1}*p_2^{k_2}*\dots p_m^{k_m} = \prod p_i^{k_i}n=p1k1p2k2pmkm=piki

m=1m=1m=1的时候是不存在合法的d1,d2d1, d2d1,d2的,这很容易证明——令d1=p1td1 = p_1^td1=p1t,那么d2=np1t=p1k−td2 = \frac {n} {p_1^t} = p_1^{k - t}d2=p1tn=p1kt,两者之和依旧是p1p_1p1的倍数,那么和nnn取gcd显然不为111。这同样证明了d1,d2d1,d2d1,d2需要互质,不然的话他们的和会是相同因数的倍数

m≠1m \ne 1m=1时,由于上文证明了d1,d2d1,d2d1,d2需要互质的关系,所以这里我们要要求d1,d2d1, d2d1,d2二者没有相同的质因子,为了简化思考我们干脆令
d1=piki,d2=nd1=∏j≠ipjkj d1 = p_i ^ {k_i}, d2 = \frac {n} {d1} = \prod_{j\ne i}p_j^{k_j} d1=piki,d2=d1n=j=ipjkj
接下来我们证明这是一组合法的答案

对于nnn的任意质因子有pi∣np_i \mid npin,设这个pip_ipi就是分给d1d1d1的质因子,那么pi∣d1p_i \mid d1pid1,并且pi∤d2p_i \nmid d2pid2。把整除换成取模的形式有d1≡0mod  pid1 \equiv 0 \mod p _ id10modpi,且d2≢0mod  pid2 \not\equiv 0 \mod p _ id20modpi,那么二者只和有d1+d2= d2 ≢0mod  pid1 + d2 =\ d2\ \not\equiv 0 \mod p _ id1+d2= d2 0modpi。也就是说d1+d2d1+d2d1+d2对于nnn的任何质因子都不整除,既然没有共同的质因子,那么二者一定是互质的,即gcd(d1+d2,n)=1gcd(d1+d2,n) = 1gcd(d1+d2,n)=1

代码实现上比较简单,用埃氏筛可以直接筛出来每个数的最小质因子,然后让这个最小质因子为d1d1d1,剩下的都归d2d2d2,看看d2d2d2是否为一即可

题外话:写这题时我一开始想了个错的证明交上去A了,写这博客的证明的时候才发现自己想错了,这个证明是我看了官方题解写的,感觉整除转取模意义下的运算的思想很实用

代码

int fac[N];
void solve() {
    for (int i = 2; i < N; i ++) {
        if (fac[i]) continue;
        for (int j = i; j < N; j += i)
            if (!fac[j])
                fac[j] = i;
    }

    int n;
    std::cin >> n;
    std::vector<PII> ans(n + 1);
    for (int i = 1; i <= n; i ++) {
        int x;
        std::cin >> x;
        int t = 1, p = fac[x];
        while (x % p == 0) x /= p, t *= p;
        if (x == 1) {
            ans[i] = {-1, -1};
            continue;
        }
        ans[i] = {t, x};
    }

    for (int i = 1; i <= n; i ++) std::cout << ans[i].first << " ";
    std::cout << "\n";
    for (int i = 1; i <= n; i ++) std::cout << ans[i].second << " ";
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值