ABC248G

套路题。

M=105

f(i) 表示路径的 gcd 恰好为 i 时候的贡献,则答案为 Mi=1i×f(i)

套路的,将限制变成路径的 gcdi 的倍数,设 g(i) 表示此时的贡献。

则有 f(i)=g(i)ij,jMf(j)

g 是很好求的。

先将 1M 中每个数的因子集合预处理求出来,然后对于一个点 i,将它加入新图 Gj 中,满足 jai

然后对于每张新图,对于每个连通块,都可以用换根轻松计算出贡献。

时间复杂度 O(nD+nlnn),其中 D 表示 1M 中因子最大的数的因子数量,为 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;
}
posted @   Kobe303  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示