题意
给定 nnn 个整数 a1,a2,…,ana_1, a_2, \dots, a_na1,a2,…,an 。
对于每个 aia_iai ,找出它的两个因数 d1>1d_1 > 1d1>1 和 d2>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) 是 aaa 和 bbb 的最大公约数),或者说不存在这样的对。
给定 nnn 个整数 a1,a2,…,ana_1, a_2, \dots, a_na1,a2,…,an 。对于每个 aia_iai 找到它的两个因数d1>1d_1 > 1d1>1 和 d2>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) 是 aaa 和 bbb 的最大公约数)或说不存在这样的对。
思路
一般涉及到因数的题目都应该联想到将其质因数分解,此题也不例外
为了方便下文用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=p1k1∗p2k2∗…pmkm=∏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=p1k−t,两者之和依旧是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=i∏pjkj
接下来我们证明这是一组合法的答案
对于nnn的任意质因子有pi∣np_i \mid npi∣n,设这个pip_ipi就是分给d1d1d1的质因子,那么pi∣d1p_i \mid d1pi∣d1,并且pi∤d2p_i \nmid d2pi∤d2。把整除换成取模的形式有d1≡0mod pid1 \equiv 0 \mod p _ id1≡0modpi,且d2≢0mod pid2 \not\equiv 0 \mod p _ id2≡0modpi,那么二者只和有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 << " ";
}