AT_ndpc2026_l 最小公倍数 题解
So_noSlack · · 题解
有一些对 这篇题解 的补充说明。
首先朴素的转移是容易的,令
可以接近
这里有一个经典 trick,把
考虑
预处理每个数的因子,就可以
然后这里还有一个小 trick,我们记录每个
把
发现
另外记得预处理每个数的所有因子,不然时间复杂度是
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 200005
#define MOD 998244353
ll n, inv[N], a[N], u[N], g[N], f[N];
vector<ll> v[N];
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n; u[1] = f[1] = 1, inv[1] = 1;
for(int i = 2; i <= n; i ++)
inv[i] = (MOD - MOD / i * inv[MOD % i] % MOD) % MOD;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= n; i ++) for(int j = i; j <= n; j += i) v[j].push_back(i);
for(int i = 1; i <= n; i ++) {
ll res = inv[i];
for(auto d : v[i]) if(d != i) res = (res - u[d] + MOD) % MOD;
u[i] = res;
}
for(auto d : v[a[1]]) g[d] = (g[d] + u[d] * f[1] % MOD * a[1] % MOD) % MOD;
for(int i = 2; i <= n; i ++) {
for(auto d : v[a[i]]) f[i] = (f[i] + g[d]) % MOD;
f[i] = f[i] * a[i] % MOD;
for(auto d : v[a[i]]) g[d] = (g[d] + u[d] * f[i] % MOD * a[i] % MOD) % MOD;
}
for(int i = 2; i <= n; i ++) cout << f[i] << "\n";
return 0;
}