codeforces 数论&容斥原理 Count GCD

本文探讨了如何计算满足特定条件的数组b的数量,通过分析数组a与b之间的关系,利用数学方法解决区间互质问题,并采用容斥原理进行求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:

 题意:

给定一个长度为 n(n≤2∗105) 的数组 a ,问有多少种长度为 n 的数组 b 满足

  • 1 ≤ b[i] ≤ m(m≤109)
  • 对于任意的 i ,满足 gcd(b[1],b[2],b[3]...b[i])=a[i]

首先 gcd 操作是递减的, gcd(b[1],b[2],b[3]...b[i])≥gcd(b[1],b[2],b[3]...b[i],b[i+1])

也就是需要满足 a[i−1]≥a[i]

且有 b[1]=a[1]

gcd(b[1],b[2],b[3]...b[i−1])=a[i−1]

gcd(b[1],b[2],b[3]...b[i−1],b[i])=a[i]

着我们有 gcd(a[i−1],b[i])=a[i] 也就是 a[i−1]=k∗a[i] (就是 a[i] 是 a[i−1] 的一个因子

所以 a[i−1]%a[i]=0

这样 a 的合法条件就讨论完了。( a[i−1]%a[i]≠0 就包含了 a[i−1]<a[i] 这个信息)

考虑每个 b[i] 的可能。

由 gcd(a[i−1],b[i])=a[i] 得, b[i] 是 a[i] 的倍数。

a[i−1]=k1∗a[i],b[i]=k2∗a[i]   且  gcd(k1,k2)=1

也就是 k2∈[1,m/a[i]]   且   k2 与 a[i−1] / a[i] 互质。

那么问题就变成了,区间互质问题。我们需要容斥来解决

严格鸽:算法数学笔记(1) 容斥原理

问题是, n=2∗105 ,用容斥的复杂度是 m 啊。

但是我们注意到, a[i] 是 a[i−1] 的因子,也就是说如果 a[i]≠a[i−1] 的情况下。

a[i]≤a[i−1]2 ,是logn级别的递减,所以我们记忆下 (m/a[i],a[i−1]/a[i]) 即可

模板:

vector<int>prime;
int num = 0;
int sum = 0;
void pr(int n) {
    prime.clear();
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            prime.push_back(i);
            while (n % i == 0)n /= i;
        }
    }
    if (n > 1)prime.push_back(n);
}
void dfs(int pos, int mul, int len) {
    if (pos == prime.size()) {
        if (len) {
            if (len % 2)sum += num / mul;
            else sum -= num / mul;
        }
        return;
    }
    dfs(pos + 1, mul, len);
    dfs(pos + 1, mul * prime[pos], len + 1);
}
map<pair<int,int>, int>mp;//记忆化
int que(int L, int k) {
    if (mp.count({ L,k }))return mp[{L, k}];
    pr(k);
    num = L; sum = 0;
    dfs(0, 1, 0);
    return mp[{L, k}] = (L - sum);
}

const int N = 2e5 + 5;
int n, a[N], m;
const int mod = 998244353;
void slove() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++)cin >> a[i];
    for (int i = 2; i <= n; i++) {
        if (a[i - 1] % a[i]) {
            cout << 0 << endl;
            return;
        }
    }
    ll ans = 1;
    for (int i = 2; i <= n; i++) {
        ans *= que(m / a[i], a[i - 1] / a[i]);
        ans %= mod;
    }
    cout << ans << endl;
}

### 关于Codeforces中的GCD问题 在Codeforces平台上存在多个涉及最大公约数(GCD)概念的问题。其中一道具有代表性的题目是编号为1025B的&ldquo;Weakened Common Divisor&rdquo;,该题由著名数学家Ildar引入了一个新的概念&mdash;&mdash;弱化公因数(WCD),即对于一系列整数对列表而言的一种特殊性质[^2]。 具体到这道题目的描述如下:给出一个长度为\(n\)的数组\(a\),目标是在所有元素上加上同一个常量\(d\)之后能够找到至少两个不同的位置其值的最大公约数大于等于2,并且要使这个加上的常量尽可能小。此题的关键在于通过计算相邻两数之差来间接获取可能存在的公共因子,进而利用这些信息推导出满足条件所需的最小增量\[d\][^4]。 为了高效解决这类基于GCD的问题,在算法设计方面通常会采用一些特定技巧: - **差分遍历**:通过对原始序列做适当变换简化问题结构; - **快速求解GCD**:借助欧几里得算法迅速定位潜在候选者; - **优化查找过程**:针对所得结果进一步筛选最优方案; 下面是一个Python版本的解决方案片段用于演示如何处理上述提到的任务逻辑: ```python from math import gcd from itertools import pairwise def min_operations_to_weak_gcd(nums): diff_gcd = 0 for prev, curr in pairwise(nums): diff_gcd = gcd(diff_gcd, abs(curr - prev)) if diff_gcd == 1: return -1 factors = get_factors(diff_gcd) result = float(&#39;inf&#39;) target_modulo = nums[0] % diff_gcd for factor in factors: candidate = ((target_modulo + diff_gcd - (nums[0] % factor)) % factor) result = min(result, candidate) return int(result) def get_factors(n): &quot;&quot;&quot;Helper function to generate all divisors.&quot;&quot;&quot; res = [] i = 1 while i*i &lt;= n: if n % i == 0: res.append(i) if i != n // i: res.append(n//i) i += 1 return sorted(res)[::-1] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值