一 原题
Mahmoud has an array a consisting of n integers. He asked Ehab to find another array b of the same lengthsuch that:
- b is lexicographically greater than or equal to a.
- bi ≥ 2.
- b is pairwise coprime: for every 1 ≤ i < j ≤ n, bi and bj are coprime, i. e. GCD(bi, bj) = 1, where GCD(w, z) is the greatest common divisor of w and z.
Ehab wants to choose a special array so he wants the lexicographically minimal array between all the variants. Can you find it?
An array x is lexicographically greater than an array y if there exists an index i such than xi > yi and xj = yj for all 1 ≤ j < i. An array x is equal to an array y if xi = yi for all 1 ≤ i ≤ n.
The first line contains an integer n (1 ≤ n ≤ 105), the number of elements in a and b.
The second line contains n integers a1, a2, ..., an (2 ≤ ai ≤ 105), the elements of a.
Output n space-separated integers, the i-th of them representing bi.
5 2 3 5 4 13
2 3 5 7 11
3 10 3 7
10 3 7
Note that in the second sample, the array is already pairwise coprime so we printed it.
二 分析
给定一个长度为n的数组a(n<=10^5,ai<=10^5)要求你给出一个新的等长数组b,b的字典序要不小于a,且b中的元素两两互素,输出所有可行的b中字典序最小的一个。
要输出的b字典序最小,我们从前往后贪心地去填数字。为了满足两两互素的条件,维护一个素数表v[maxp],如果素数p已经是先前某个b中元素的素因子,v[p]设置为true。注意,bi的上界题目中并没有规定,但前10^5个素数组成的数组一定是一个合法解,根据素数约占前n个数的1/ln(n),我在实现时把bi的上界定位了1e7.
假设我们已经搞定了b中前k-1个数,如果b的前k-1个数和a都相同,那么bk就要大于等于ak,我们从ak开始枚举可行解,每次验证的代价是一次质因数分解;如果b的前k-1个数中有大于a的,那么bk设置为当前为使用过的最小素数就行了。
三 代码
#include <cstdio>
const int maxn = 1e7 + 5;
int n, a[maxn], d[maxn];
bool v[maxn];
void prepare() {
for (int i = 2; i < maxn; i++) {
if (d[i] != 0) continue;
for (int j = i; j < maxn; j += i) d[j] = i;
}
}
int main() {
prepare();
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
int idx = 0, x;
while (idx < n) {
bool ok = true;
x = a[idx];
while (x != 1) {
if (v[d[x]]) { ok = false; break; }
x /= d[x];
}
if (ok) {
x = a[idx];
while (x != 1) {
v[d[x]] = true;
x /= d[x];
}
idx++;
continue;
}
while (!ok) {
ok = true;
x = ++a[idx];
while (x != 1) {
if (v[d[x]]) { ok = false; break; }
x /= d[x];
}
}
x = a[idx];
while (x != 1) {
v[d[x]] = true;
x /= d[x];
}
idx++;
break;
}
int p = 2;
while (idx < n) {
for (;; p++) {
if (d[p] != p || v[p]) continue;
a[idx++] = p;
p++; break;
}
}
for (int i = 0; i < n; i++) printf("%d ", a[i]);
return 0;
}