短短题解:CF1750D Count GCD
把要求的 \(\gcd(b_1, b_2, \dots, b_i) = a_i\) 写成 \(\gcd(\gcd(b_1, b_2, \dots, b_{i-1}), b_i) = a_i\),这等价于要求 \(\gcd(a_{i - 1}, b_i) = a_i\),其中定义 \(a_0\) 为 \(\gcd\) 的单位元;这就已经是充要的了。
对 \(\gcd(a_{i - 1}, b_i) = a_i\) 做观察:
-
\[\gcd(a_{i-1}, b_i) = a_i \implies a_i \mid a_{i-1} \land a_i \mid b_i \]
-
\[\gcd(a_{i-1}, b_i) = a_i \iff \gcd(\frac{a_{i-1}}{a_i}, \frac{b_i}{a_i}) = 1 \]
因此对于 \(2 \leq i \leq n\) 的每个 \(i\),必须都有 \(a_{i} \mid a_{i-1}\),否则不存在任何符合条件的 \(b\) 序列,直接输出 0。
接下来是计数:满足 \(b_1 = a_1\),且对于 \(2 \leq i \leq n\) 的每个 \(i\),有 \(1 \leq b_i \leq m\) 且 \(\gcd(\frac{a_{i-1}}{a_i}, \frac{b_i}{a_i}) = 1\) 的序列 \(b\) 的个数。
注意到在位置 \(i\),\(b_i\) 的合法性与其他位置 \(j\) 的 \(b_j\) 均无关,因此可以使用乘法原理合并每个位置上的答案。
做点简化,设 \(\frac{a_{i-1}}{a_i}\) 为 \(x\),\(\frac{b_i}{a_i}\) 为 \(y\)。问题即变为统计满足 \(1 \leq y \cdot a_i \leq m\),即 \(1 \leq y \leq \lfloor \frac{m}{a_i} \rfloor\) 且 \(\gcd(x, y) = 1\) 的 \(y\) 的个数。
这是莫比乌斯反演例题:
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 200000 + 1, P = 998244353;
int a[N];
void solve() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
auto getprms = [](int x) {
vector<int> res;
for (int i = 2; i * i <= x; ++i) if (x % i == 0) {
x /= i;
res.push_back(i);
while (x % i == 0) {
x /= i;
}
}
if (x != 1) {
res.push_back(x);
}
return res;
};
int ans = 1;
for (int i = 2; i <= n; ++i) {
if (a[i - 1] % a[i]) {
cout << "0\n";
return ;
}
vector<int> res = getprms(a[i - 1] / a[i]);
int sm = 0;
auto dfs = [&](auto &&self, int dep, int mul, int mu) {
if (dep == (int)res.size()) {
sm += m / a[i] / mul * mu;
return ;
}
self(self, dep + 1, mul, mu);
self(self, dep + 1, mul * res[dep], -mu);
};
dfs(dfs, 0, 1, 1);
ans = (long long)ans * sm % P;
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
posted on 2026-01-04 10:06 SkyWave2022 阅读(2) 评论(0) 收藏 举报
浙公网安备 33010602011771号