首页 > 其他分享 >ABC248G

ABC248G

时间:2022-11-08 11:00:52浏览次数:50  
标签:sz int vi dfs fa 因子 ABC248G

套路题。

设 \(M=10^5\)。

设 \(f(i)\) 表示路径的 \(\gcd\) 恰好为 \(i\) 时候的贡献,则答案为 \(\sum_{i=1}^M i\times f(i)\)。

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

则有 \(f(i)=g(i)-\sum_{i\mid j,j\le M}f(j)\)。

\(g\) 是很好求的。

先将 \(1\sim M\) 中每个数的因子集合预处理求出来,然后对于一个点 \(i\),将它加入新图 \(G_j\) 中,满足 \(j\mid a_i\)。

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

时间复杂度 \(\mathcal O(nD+n\ln n)\),其中 \(D\) 表示 \(1\sim 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;
}

标签:sz,int,vi,dfs,fa,因子,ABC248G
From: https://www.cnblogs.com/Kobe303/p/16868928.html

相关文章