D. Count GCD
D. Count GCD
You are given two integers $n$ and $m$ and an array $a$ of $n$ integers. For each $1 \le i \le n$ it holds that $1 \le a_i \le m$.
Your task is to count the number of different arrays $b$ of length $n$ such that:
- $1 \le b_i \le m$ for each $1 \le i \le n$, and
- $\gcd(b_1,b_2,b_3,...,b_i) = a_i$ for each $1 \le i \le n$.
Here $\gcd(a_1,a_2,\dots,a_i)$ denotes the greatest common divisor (GCD) of integers $a_1,a_2,\ldots,a_i$.
Since this number can be too large, print it modulo $998\,244\,353$.
Input
Each test consist of multiple test cases. The first line contains a single integer $t$ ($1 \le t \le 100$) — the number of test cases. The description of test cases follows.
The first line of each test case contains two integers $n$ and $m$ ($1 \le n \le 2 \cdot 10^5$, $1 \le m \le 10^9$) — the length of the array $a$ and the maximum possible value of the element.
The second line of each test case contains $n$ integers $a_1, a_2, \ldots, a_n$ ($1 \le a_i \le m$) — the elements of the array $a$.
It is guaranteed that the sum of $n$ across all test cases doesn't exceed $2 \cdot 10^5$.
Output
For each test case, print a single integer — the number of different arrays satisfying the conditions above. Since this number can be large, print it modulo $998\,244\,353$.
Example
input
5 3 5 4 2 1 2 1 1 1 5 50 2 3 5 2 3 4 1000000000 60 30 1 1 2 1000000000 1000000000 2
output
3 1 0 595458194 200000000
Note
In the first test case, the possible arrays $b$ are:
- $[4,2,1]$;
- $[4,2,3]$;
- $[4,2,5]$.
In the second test case, the only array satisfying the demands is $[1,1]$.
In the third test case, it can be proven no such array exists.
解题思路
由于有$\gcd(b_1,b_2,b_3,...,b_{i-1}) = a_{i-1}$,因此容易发现$a_{i} = \gcd(b_1,b_2,b_3,...,b_{i-1}, b_{i}) = \gcd(a_{i-1}, b_{i})$。因此如果$a_{i} \nmid a_{i-1}$,那么就一定无解,即满足条件的$b$数组数量为$0$。
否则,由于$a_{i} = \gcd(a_{i-1}, b_{i})$,因此$b_{i}$应该是$a_{i}$的倍数,即$b_{i} = k \cdot a_{i}$,其中$1 \leq k \leq \left\lfloor \frac{m}{a_i} \right\rfloor$。同时还需要注意到$a_{i-1}, b_{i}$要满足$\gcd(\frac{a_{i-1}}{a_i}, \frac{b_i}{a_i}) = 1$,即$a_{i-1}$和$b_{i}$除去最大公因子后,$\frac{b_i}{a_i}$应该与$\frac{a_{i-1}}{a_i}$互质,否则最大公因子就不是$a_i$了。因此选择的$k$还应该满足不能含有$\frac{a_{i-1}}{a_i}$的任何一个质因子,即满足$\gcd(k, \frac{a_{i-1}}{a_i}) = 1$。这个就可以用容斥原理来实现。
因此需要先对$\frac{a_{i-1}}{a_i}$分解质因子,由于在不超过${10}^{9}$的数中分解得到不同的质因子的个数最多不超过$9$个($2 \times 3 \times 5 \times 7 \times 11 \times 13 \times 17 \times 19 \times 23 = 223\,092\,870 < {10}^{9}$),因此为了实现方便这里容斥原理可以通过二进制枚举的方式来实现。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 const int N = 2e5 + 10, mod = 998244353; 7 8 int a[N]; 9 10 vector<int> divide(int x) { 11 vector<int> fs; 12 for (int i = 2; i <= x / i; i++) { 13 if (x % i == 0) { 14 fs.push_back(i); 15 while (x % i == 0) { 16 x /= i; 17 } 18 } 19 } 20 if (x > 1) fs.push_back(x); 21 return fs; 22 } 23 24 void solve() { 25 int n, m; 26 scanf("%d %d", &n, &m); 27 for (int i = 0; i < n; i++) { 28 scanf("%d", a + i); 29 } 30 LL ret = 1; 31 for (int i = 1; i < n; i++) { 32 if (a[i - 1] % a[i]) { // a[i]不能整除a[i-1],无解 33 ret = 0; 34 break; 35 } 36 else { 37 // a[i-1]/a[i]要与k互质 38 vector<int> fs = divide(a[i - 1] / a[i]); // 分解质因数 39 LL k = m / a[i], s = 0; // s是容斥原理的结果,即满足条件的k的个数 40 for (int i = 0; i < 1 << fs.size(); i++) { 41 int prod = 1, cnt = 0; // prod是分母的乘积,cnt是乘了几个数 42 for (int j = 0; j < fs.size(); j++) { 43 if (i >> j & 1) prod *= fs[j], cnt++; 44 } 45 // 根据容斥原理的公式,如果分母乘了奇数个数,那么符号是-号,否则是+号 46 if (cnt & 1) s -= k / prod; 47 else s += k / prod; 48 } 49 ret = ret * s % mod; // 乘法原理 50 } 51 } 52 printf("%d\n", ret); 53 } 54 55 int main() { 56 int t; 57 scanf("%d", &t); 58 while (t--) { 59 solve(); 60 } 61 62 return 0; 63 }
2024-02-28 更新:完善题解与代码。
与上面的分析一样,每个 $b_i$ 能取的数的数量就是 $1 \sim k$ $(k = \lfloor \frac{m}{a_i} \rfloor)$ 中与 $\frac{a_{i-1}}{a_i}$ 互质的数的数量,最后根据乘法原理把每个 $b_i$ 能取的数的数量全部乘上就是答案。
而 $1 \sim k$ 中与 $\frac{a_{i-1}}{a_i}$ 互质的数的数量,等价于先求出 $1 \sim k$ 中与 $\frac{a_{i-1}}{a_i}$ 不互质的数的数量,记作 $s$,再令 $k$ 减去 $s$。假设 $\frac{a_{i-1}}{a_i}$ 的不同质因子有 $c$ 个分别是 $p_1, \ldots p_c$,由上面分析知道 $c \leq 9$。那么 $s$ 就是 $1 \sim k$ 中能被 $p_1, \ldots p_c$ 中的至少一个数整除的数的数量。因此就可以用容斥原理来求出 $s$,参考能被整除的数。
另外由于 $a_i \mid a_{i-1}$,因此每个 $a_i$ 都能整除 $a_1$,意味着我们只需分解 $a_1$ 的质因子即可,其他 $a_i$ 的质因子必然被 $a_1$ 的包含。
AC 代码如下,时间复杂度为 $O(2^9 \cdot 9 \cdot n + \log{m})$
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10, mod = 998244353;
int a[N];
void solve() {
int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
}
for (int i = 2; i <= n; i++) {
if (a[i - 1] % a[i]) {
printf("0\n");
return;
}
}
vector<int> p;
int t = a[1];
for (int i = 2; i * i <= t; i++) {
if (t % i == 0) {
p.push_back(i);
while (t % i == 0) {
t /= i;
}
}
}
if (t > 1) p.push_back(t);
int ret = 1;
for (int i = 2; i <= n; i++) {
int k = m / a[i], t = a[i - 1] / a[i];
vector<int> q;
for (auto &x : p) {
if (t % x == 0) q.push_back(x);
}
int s = 0;
for (int j = 1; j < 1 << q.size(); j++) {
int t = k, c = 0;
for (int k = 0; k < q.size(); k++) {
if (j >> k & 1) t /= q[k], c++;
}
if (c & 1) s = (s + t) % mod;
else s = (s - t) % mod;
}
ret = 1ll * ret * (k - s) % mod;
}
printf("%d\n", (ret + mod) % mod);
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}
参考资料
CodeTON Round 3 (Div. 1 + Div. 2) Editorial:https://codeforces.com/blog/entry/108504
CodeTON Round 3 (Div. 1 + Div. 2, Rated, Prizes!) A - E:https://zhuanlan.zhihu.com/p/581011028
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16902713.html