F - Subsequence LCM

F - Subsequence LCM

Problem Statement

You are given a sequence of positive integers $A=(A_1,A_2,\dots,A_N)$ of length $N$ and a positive integer $M$. Find the number, modulo $998244353$, of non-empty and not necessarily contiguous subsequences of $A$ such that the least common multiple (LCM) of the elements in the subsequence is $M$. Two subsequences are distinguished if they are taken from different positions in the sequence, even if they coincide as sequences. Also, the LCM of a sequence with a single element is that element itself.

Constraints

  • $1 \leq N \leq 2 \times 10^5$
  • $1 \leq M \leq 10^{16}$
  • $1 \leq A_i \leq 10^{16}$
  • All input values are integers.

Input

The input is given from Standard Input in the following format:

$N$ $M$
$A_1$ $A_2$ $\ldots$ $A_N$

Output

Print the answer.


Sample Input 1

4 6
2 3 4 6

Sample Output 1

5

The subsequences of $A$ whose elements have an LCM of $6$ are $(2,3),(2,3,6),(2,6),(3,6),(6)$; there are five of them.


Sample Input 2

5 349
1 1 1 1 349

Sample Output 2

16

Note that even if some subsequences coincide as sequences, they are distinguished if they are taken from different positions.


Sample Input 3

16 720720
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

Sample Output 3

2688

 

解题思路

  一些技巧。要对 $a_1, \ldots, a_n$ 求 $\gcd$ 或 $\mathrm{lcm}$,先质因数分解,使得每个 $a_i$ 都有共同的质因子 $P$(不存在则用 $P^0$ 表示):

\begin{align*}
a_1 & = P_{1}^{\alpha_{1,1}} P_{2}^{\alpha_{1,2}} \cdots P_{k}^{\alpha_{1,k}} \\
a_2 & = P_{1}^{\alpha_{2,1}} P_{2}^{\alpha_{2,2}} \cdots P_{k}^{\alpha_{2,k}} \\
& \;\;\vdots \\
a_i & = P_{1}^{\alpha_{i,1}} P_{2}^{\alpha_{i,2}} \cdots P_{k}^{\alpha_{i,k}} \\
& \;\;\vdots \\
a_n & = P_{1}^{\alpha_{n,1}} P_{2}^{\alpha_{n,2}} \cdots P_{k}^{\alpha_{n,k}} \\
\end{align*}

  那么就有:

\begin{align*}
\gcd(a_1, \ldots, a_n) &= P_{1}^{\min\{\alpha_{i,1}\}} P_{2}^{\min\{\alpha_{i,2}\}} \cdots P_{k}^{\min\{\alpha_{i,k}\}} \\
\mathrm{lcm}(a_1, \ldots, a_n) &= P_{1}^{\max\{\alpha_{i,1}\}} P_{2}^{\max\{\alpha_{i,2}\}} \cdots P_{k}^{\max\{\alpha_{i,k}\}}
\end{align*}

  由于子序列的 $\mathrm{lcm}$ 等于确定的 $m$,所以对 $m$ 进行质因数分解,有 $m = P_{1}^{\alpha_{1}} P_{2}^{\alpha_{2}} \cdots P_{k}^{\alpha_{k}}$,容易知道在 $10^{16}$ 内一个数最多有 $13$ 个不同的质因子,因此这里的 $k$ 最大为 $13$。同时这样的子序列中每个元素必然满足 $a_i \mid m$,因此一开始先把 $a_i \nmid m$ 的元素删掉,那么剩下的元素必定都能表示成 $P_{1}^{\beta_{1}} P_{2}^{\beta_{2}} \cdots P_{k}^{\beta_{k}}$,且 $\beta_{i} \leq \alpha_{i}$。

  根据上面提到求 $\mathrm{lcm}$ 的技巧,如果每个 $P_{i}$ 都有 $\max\{\beta_i\} = \alpha_i$,那么该子序列的 $\mathrm{lcm}$ 才能为 $m$。也就是说选出来的子序列中,在每一个 $P_i$ 上都至少存在一个元素该项的次幂为 $\alpha_i$。为此我们可以用 $k$ 位的二进制进行状态压缩,对于每一个元素,如果该元素质因数分解后 $P_i$ 项的次幂恰好是 $\alpha_i$,那么置第 $i$ 位为 $1$,否则置为 $0$。

  所以现在的问题变成了有多少种选择方案,使得选出来元素对应的二进制状态的按位或等于 $2^{k}-1$(即 $k$ 个位均为 $1$)。可以用 dp 解决,定义 $f(i,j)$ 表示从前 $i$ 个元素中选出状态按位或等于 $j$ 的方案数量。考虑从 $f(i,j)$ 可以转移到哪些状态,状态转移方程为 $f(i+1,j) \mathrm{+}\mathrm{=} f(i,j)$(不选择第 $i$ 个元素);$f(i+1,j \mid \mathrm{st}_i) \mathrm{+}\mathrm{=} f(i,j)$(选择第 $i$ 个元素,$a_i$ 的状态表示为 $\mathrm{st}_i$)。

  这样做的时间复杂度是 $O(n \cdot 2^{13})$,会超时。注意到最多有 $2 \cdot 10^5$ 个元素,而所有元素的状态最多有 $2^{13}$ 种,因此我们可以统计状态 $i$ 的数量表示为 $\mathrm{cnt}_i$。那么 $f(i,j)$ 表示从前 $i$ 个状态中选出按位或等于 $j$ 的方案数量。状态转移方程为 $f(i+1,j) \mathrm{+}\mathrm{=} f(i,j)$;$f(i+1,j \mid i) \mathrm{+}\mathrm{=} \left(2^{\mathrm{cnt}_i} - 1\right) \cdot f(i,j)$。

  我的代码实现是通过类似 01 背包的方式优化掉第一维,预处理出 $2^i$。直接用 $O(\sqrt{m})$ 的复杂度质因数分解 $m$。还有要记得特判 $m=1$ 的情况。

  AC 代码如下,时间复杂度为 $O(\sqrt{m} + 2^{2 \cdot 13})$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 2e5 + 5, M = 1 << 13, mod = 998244353;

int cnt[M];
int f[M];
int p[N];

int main() {
    int n;
    LL m;
    scanf("%d %lld", &n, &m);
    vector<LL> fs;
    LL t = m;
    for (LL i = 2; i * i <= t; i++) {
        if (t % i == 0) {
            LL p = 1;
            while (t % i == 0) {
                p *= i;
                t /= i;
            }
            fs.push_back(p);
        }
    }
    if (t > 1) fs.push_back(t);
    for (int i = 1; i <= n; i++) {
        LL x;
        scanf("%lld", &x);
        if (m % x) continue;
        int t = 0;
        for (int j = 0; j < fs.size(); j++) {
            if (x % fs[j] == 0) t |= 1 << j;
        }
        cnt[t]++;
    }
    p[0] = 1;
    for (int i = 1; i <= n; i++) {
        p[i] = p[i - 1] * 2 % mod;
    }
    f[0] = 1;
    for (int i = 0; i < 1 << fs.size(); i++) {
        if (!cnt[i]) continue;
        for (int j = (1 << fs.size()) - 1; j >= 0; j--) {
            f[j | i] = (f[j | i] + (p[cnt[i]] - 1ll) * f[j]) % mod;
        }
    }
    printf("%d", f[(1 << fs.size()) - 1] - (m == 1));
    
    return 0;
}

 

参考资料

  Editorial - AtCoder Beginner Contest 349:https://atcoder.jp/contests/abc349/editorial/9801

  ABC349F题 Subsequence LCM讲解(DP暴力做法 or 高维前缀和):https://www.bilibili.com/video/BV1jr42157Fa/

posted @ 2024-04-19 14:59  onlyblues  阅读(41)  评论(0编辑  收藏  举报
Web Analytics