1 条题解
-
0
考虑在 和 之间连边,题目相当于在这张图上撒 个关键点,求距离每个关键点最近且非本身的关键点的最小编号。对每个点记录距离该点最近和第二近的关键点距离与编号,一遍
BFS即可,但是常数太大,不开 O2 难以通过。设 表示 的质因子个数,则 $\mathrm{dis}(i,j)=\omega(i)+\omega(j)-2\omega(\gcd(i,j))$。考虑枚举 ,那么减号后面的部分就确定了,对于一个固定的 ,我们显然要让 这一二元组最小,其中 表示 值为 的最小位置。
考虑枚举 的倍数 ,求出 ,设为 以及取到最小值的位置为 。 那么对于所有 ,我们用 和 互相更新。 就相当于上面的 ,而 充当了使得 最小的 。
每个 都会被枚举到,因此算法正确。时间复杂度是调和级数的线性对数。由于小常数,成功拿到了最优解(2021.12.19)。
const int N = 1e6 + 5; int n, mx, a[N], buc[N], ans[N], fc[N]; pii dis[N]; int cnt, vis[N], pr[N], mpr[N], chk[N]; void sieve() { dis[1] = {N, 0}; for(int i = 2; i <= mx; i++) { dis[i] = {N, 0}; if(!vis[i]) pr[++cnt] = i, mpr[i] = i; for(int j = 1; j <= cnt && i * pr[j] <= mx; j++) { vis[i * pr[j]] = 1, mpr[i * pr[j]] = pr[j]; if(i % pr[j] == 0) break; } chk[i] = chk[i / mpr[i]] + 1; } } int main() { cin >> n; for(int i = 1; i <= n; i++) { a[i] = read(), cmax(mx, a[i]); if(buc[a[i]]) { ans[i] = buc[a[i]]; if(!ans[buc[a[i]]]) ans[buc[a[i]]] = i; } else buc[a[i]] = i; } sieve(); for(int i = 1; i <= mx; i++) { pii best = {N, 0}; for(int j = i, dv = 1; j <= mx; j += i, dv++) if(buc[j]) cmin(best, (pii){chk[dv], buc[j]}); for(int j = i, dv = 1; j <= mx; j += i, dv++) if(buc[j] != best.se && buc[j]) cmin(dis[j], (pii){best.fi + chk[dv], best.se}), cmin(dis[a[best.se]], (pii){best.fi + chk[dv], buc[j]}); if(buc[i] && !ans[buc[i]]) ans[buc[i]] = dis[i].se; } for(int i = 1; i <= n; i++) print(ans[i]), pc('\n'); return flush(), 0; }
- 1
信息
- ID
- 4455
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者