ABC248G
套路题。
设 M=105。
设 f(i) 表示路径的 gcd 恰好为 i 时候的贡献,则答案为 ∑Mi=1i×f(i)。
套路的,将限制变成路径的 gcd 为 i 的倍数,设 g(i) 表示此时的贡献。
则有 f(i)=g(i)−∑i∣j,j≤Mf(j)。
g 是很好求的。
先将 1∼M 中每个数的因子集合预处理求出来,然后对于一个点 i,将它加入新图 Gj 中,满足 j∣ai。
然后对于每张新图,对于每个连通块,都可以用换根轻松计算出贡献。
时间复杂度 O(nD+nlnn),其中 D 表示 1∼M 中因子最大的数的因子数量,为 128。
但是常数很小,无压力跑过。
Code:
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
typedef long long ll;
typedef vector <int> vi;
const int N = 100000, mod = 998244353;
int n;
int a[N+5];
vi E[N+5], g[N+5], p[N+5];
vi tmp;
bool vis[N+5], mark[N+5];
int f[N+5];
int sz[N+5];
void dfs(int u, int fa) {
sz[u] = vis[u] = 1, tmp.pb(u);
for (int v : E[u]) if (v != fa && mark[v]) dfs(v, u), sz[u] += sz[v];
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= N; ++i)
for (int j = i; j <= N; j += i)
p[j].pb(i);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
for (int j : p[a[i]]) g[j].push_back(i);
}
for (int i = 1, u, v; i < n; ++i) scanf("%d%d", &u, &v), E[u].pb(v), E[v].pb(u);
for (int i = 1; i <= N; ++i) {
for (int x : g[i]) mark[x] = 1, vis[x] = 0;
for (int x : g[i])
if (!vis[x]) {
tmp.clear();
dfs(x, 0);
for (int v : tmp) f[i] = (f[i] + 1ll * sz[v] * (sz[x] - sz[v]) % mod) % mod;
f[i] = (f[i] + 1ll * sz[x] * (sz[x] - 1) / 2 % mod) % mod;
}
for (int x : g[i]) mark[x] = 0;
}
for (int i = N; i; --i)
for (int j = i + i; j <= N; j += i)
f[i] = (f[i] - f[j] + mod) % mod;
int ans = 0;
for (int i = 1; i <= N; ++i) ans = (ans + 1ll * i * f[i] % mod) % mod;
printf("%d", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话