F - Subsequence LCM

F - Subsequence LCM

Problem Statement

You are given a sequence of positive integers A=(A1,A2,,AN) 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

  • 1N2×105
  • 1M1016
  • 1Ai1016
  • All input values are integers.

Input

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

N M
A1 A2 AN

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

 

解题思路

  一些技巧。要对 a1,,angcdlcm,先质因数分解,使得每个 ai 都有共同的质因子 P(不存在则用 P0 表示):

a1=P1α1,1P2α1,2Pkα1,ka2=P1α2,1P2α2,2Pkα2,kai=P1αi,1P2αi,2Pkαi,kan=P1αn,1P2αn,2Pkαn,k

  那么就有:

gcd(a1,,an)=P1min{αi,1}P2min{αi,2}Pkmin{αi,k}lcm(a1,,an)=P1max{αi,1}P2max{αi,2}Pkmax{αi,k}

  由于子序列的 lcm 等于确定的 m,所以对 m 进行质因数分解,有 m=P1α1P2α2Pkαk,容易知道在 1016 内一个数最多有 13 个不同的质因子,因此这里的 k 最大为 13。同时这样的子序列中每个元素必然满足 aim,因此一开始先把 aim 的元素删掉,那么剩下的元素必定都能表示成 P1β1P2β2Pkβk,且 βiαi

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

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

  这样做的时间复杂度是 O(n213),会超时。注意到最多有 2105 个元素,而所有元素的状态最多有 213 种,因此我们可以统计状态 i 的数量表示为 cnti。那么 f(i,j) 表示从前 i 个状态中选出按位或等于 j 的方案数量。状态转移方程为 f(i+1,j)+=f(i,j)f(i+1,ji)+=(2cnti1)f(i,j)

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

  AC 代码如下,时间复杂度为 O(m+2213)

#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 @   onlyblues  阅读(80)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示