当前位置: 首页 > news >正文

[GESP202506 五级] 最大公因数

题目描述

对于两个正整数 a,ba,ba,b,他们的最大公因数记为 gcd⁡(a,b)\gcd(a,b)gcd(a,b)。对于 k>3k > 3k>3 个正整数 c1,c2,…,ckc_1,c_2,\dots,c_kc1,c2,,ck,他们的最大公因数为:

gcd⁡(c1,c2,…,ck)=gcd⁡(gcd⁡(c1,c2,…,ck−1),ck)\gcd(c_1,c_2,\dots,c_k)=\gcd(\gcd(c_1,c_2,\dots,c_{k-1}),c_k)gcd(c1,c2,,ck)=gcd(gcd(c1,c2,,ck1),ck)

给定 nnn 个正整数 a1,a2,…,ana_1,a_2,\dots,a_na1,a2,,an 以及 qqq 组询问。对于第 i(1≤i≤q)i(1 \le i \le q)i(1iq) 组询问,请求出 a1+i,a2+i,…,an+ia_1+i,a_2+i,\dots,a_n+ia1+i,a2+i,,an+i 的最大公因数,也即 gcd⁡(a1+i,a2+i,…,an+i)\gcd(a_1+i,a_2+i,\dots,a_n+i)gcd(a1+i,a2+i,,an+i)

输入格式

第一行,两个正整数 n,qn,qn,q,分别表示给定正整数的数量,以及询问组数。

第二行,nnn 个正整数 a1,a2,…,ana_1,a_2,\dots,a_na1,a2,,an

输出格式

输出共 qqq 行,第 iii 行包含一个正整数,表示 a1+i,a2+i,…,an+ia_1+i,a_2+i,\dots,a_n+ia1+i,a2+i,,an+i 的最大公因数。

输入输出样例 #1

输入 #1

5 3
6 9 12 18 30

输出 #1

1
1
3

输入输出样例 #2

输入 #2

3 5
31 47 59

输出 #2

4
1
2
1
4

说明/提示

对于 60%60\%60% 的测试点,保证 1≤n≤1031 \le n \le 10^31n1031≤q≤101 \le q \le 101q10

对于所有测试点,保证 1≤n≤1051 \le n \le 10^51n1051≤q≤1051 \le q \le 10^51q1051≤ai≤10001 \le a_i \le 10001ai1000

提交链接

https://www.luogu.com.cn/problem/P13014

思路分析

🔍 暴力解法,适用于 60%60\%60% 数据

我们观察题目的形式,会发现每次查询是对整个数组加上一个偏移量 iii,然后再计算它们的最大公因数。这种问题在数据范围较小时,可以直接暴力解决。

1. 暴力模拟每个询问

  • 对于每次询问 iii,我们把数组中每个元素都加上 iii,得到一个新的数组。

  • 然后,我们对新数组依次计算 gcd

  • 由于 gcd 满足结合律,我们可以通过从前往后扫描数组,依次更新当前的 gcd 值。

例如,若有数组:

a = [6, 9, 12]
i = 1
则变为 [7, 10, 13]
然后计算 gcd(7, 10, 13)

实现方式:

  • 初始设 gcd=a[0]+igcd = a[0] + igcd=a[0]+i
  • 然后遍历其余元素:gcd=gcd⁡(gcd,a[j]+i)gcd = \gcd(gcd, a[j] + i)gcd=gcd(gcd,a[j]+i)

最终的 gcdgcdgcd 就是这一组询问的答案。

2. 算法复杂度分析

  • 外层:询问数量为 qqq
  • 内层:每次询问需要遍历 nnn 个元素
  • 总体复杂度为 O(q⋅n)O(q \cdot n)O(qn)

对于题目中说的 60%60\%60% 数据范围(n≤1000,q≤10n \le 1000, q \le 10n1000,q10),这个复杂度是可以接受的:1000×10=1041000 \times 10 = 10^41000×10=104gcdgcdgcd 计算。


参考代码

#include <bits/stdc++.h>
using namespace std;int main()
{int n, q;cin >> n >> q;   //n个数字  q次询问vector<int> a(n);for (int &i : a)cin >> i;for(int i = 1; i <= q; i++)  //q次询问{int gcd = a[0] + i;for(int j = 1; j < n; j++)gcd = __gcd(gcd , a[j] + i);cout << gcd << endl;}return 0;
}

✅ 解题思路(优化做法,适用于 100%100\%100% 数据)

🔍 问题本质转化

我们要计算每次查询:gcd(a₁ + i, a₂ + i, ..., aₙ + i)

qqq 次对 nnn 个数求 GCD,暴力做法时间复杂度是 O(q⋅n)O(q \cdot n)O(qn),显然会超时。但我们可以利用 GCD 的平移不变性结合律 优化这个过程。

🧠 核心数学性质

一个关键性质是:

  • gcd(x + a₁, x + a₂, ..., x + aₙ) = gcd(x + a₁, a₂ - a₁, a₃ - a₁, ..., aₙ - a₁)

也就是说,我们可以把所有的 ai+xa_i + xai+x 表达成:gcd(a₁ + x, d₂, d₃, ..., dₙ)

其中 di=ai−a1d_i = a_i - a₁di=aia1,即所有数与第一个数的差。

💡 为什么这个公式成立?

这个公式的核心原理来源于 GCD 的不变性GCD 对加减法的封闭性

对于任意整数 u,vu, vu,v,都有:gcd(u, v) = gcd(u, v - u)

这是我们在辗转相除法(欧几里得算法)中使用的基本规则。

🧠 用在这个问题里,我们怎么理解?

我们要求的是:g = gcd(x + a₁, x + a₂, ..., x + aₙ)

我们可以把所有的数都减去 (x+a1)(x + a₁)(x+a1),即:

(x + a₂) - (x + a₁) = a₂ - a₁  
(x + a₃) - (x + a₁) = a₃ - a₁  
...  
(x + aₙ) - (x + a₁) = aₙ - a₁

根据 gcdgcdgcd 的性质,这种减法不会改变最终的 gcdgcdgcd 结果。所以我们可以把上面的式子变形为:

  • gcd(x + a₁, a₂ - a₁, a₃ - a₁, ..., aₙ - a₁)

✅ 举个例子理解

假设:a = [6, 9, 12]

查询值:x = 1

我们要求:gcd(6 + 1, 9 + 1, 12 + 1) = gcd(7, 10, 13)

现在按照公式转换:

x + a₁ = 7  
差值:  
9 - 6 = 3  
12 - 6 = 6

转化为:gcd(7, 3, 6)

继续计算:

gcd(7, 3) = 1  
gcd(1, 6) = 1

结果是:111,与原始计算:gcd(7, 10, 13) 得到的结果一致。

⚙️ 实现方式

我们可以将这些差值的 GCD 预处理出来,代码如下:

int g = a[1] - a[0];
for (int i = 2; i < n; i++) {g = __gcd(g, abs(a[i] - a[0]));
}

然后每次查询只需要计算:

__gcd(a[0] + x, g);

这就将 O(q⋅n)O(q \cdot n)O(qn) 优化成了 O(n+qlog⁡A)O(n + q \log A)O(n+qlogA)

🔧 代码分析

差值 gcd 预处理

int g = a[1] - a[0];
for(int i = 2; i < n; i++) 
{g = __gcd(g , abs(a[i] - a[0]));
}

这段代码做的是:将所有差值的 gcdgcdgcd 预处理出来,时间复杂度 O(n)O(n)O(n)

查询处理:
for(int i = 1; i <= q; i++) {int gcd = __gcd(g , a[0] + i);cout << gcd << endl;
}

每次查询的时间复杂度是 O(log⁡A)O(\log A)O(logA)

📌 时间复杂度分析

  • 差值 gcdgcdgcd 预处理:O(n)O(n)O(n)
  • 每次查询:O(log⁡A)O(\log A)O(logA),总共 qqq 次,复杂度为 O(qlog⁡A)O(q \log A)O(qlogA)
  • 总体时间复杂度:O(n+qlog⁡A)O(n + q \log A)O(n+qlogA)

这个复杂度对于题目给定的最大范围 n,q≤105n, q \le 10^5n,q105 是完全可以接受的。

参考代码

#include <bits/stdc++.h>
using namespace std;int main()
{int n, q;cin >> n >> q; // n个数字  q次询问vector<int> a(n);for (int &i : a)cin >> i;int g = 0;for (auto it : a)g = __gcd(g, abs(it - a[0]));for (int i = 1; i <= q; i++) // q次询问{int gcd = __gcd(g, a[0] + i);cout << gcd << endl;}return 0;
}
http://www.lryc.cn/news/614355.html

相关文章:

  • 豆包新模型矩阵+PromptPilot:AI开发效率革命的终极方案
  • 矩阵中的最长递增路径-记忆化搜索
  • Maven/Gradle常用命令
  • STM32CubeMX(十二)SPI驱动W25Qxx(Flash)
  • 恶臭气体在线监测仪器:实时、连续监测环境中恶臭气体浓度
  • c++初学day1(类比C语言进行举例,具体原理等到学到更深层的东西再进行解析)
  • (已解决)IDEA突然无法使用Git功能
  • 杂谈 001 · VScode / Copilot 25.08 更新
  • 关于“致命错误:‘https://github.com/....git/‘ 鉴权失败”
  • Spring Boot 结合 CORS 解决前端跨域问题
  • 《常见高频算法题 Java 解法实战精讲(3):排序与二叉树》
  • 2025小程序怎么快速接入美团核销,实现自动化核销
  • Ignite 资源注入核心:GridResourceProcessor 详解
  • Nestjs框架: 接口安全与响应脱敏实践 --- 从拦截器到自定义序列化装饰器
  • PEV2(PostgreSQL Explain Visualizer 2)
  • Windows 定时开关机终极指南
  • 为什么通过CreateThread创建的线程调用C/C++运行库函数不稳定
  • 代码随想录刷题Day26
  • 【Git】企业级使用
  • 路由器不能上网的解决过程
  • GPT-5与国内头部模型厂商主要能力对比
  • GPT-5 全面解析与 DeepSeek 实战对比:推理、工具调用、上下文与成本
  • 汽车电子:现代汽车的“神经中枢“
  • 宁商平台税务新政再升级:精准施策,共筑金融投资新生态
  • ubuntu alias命令使用详解
  • 仅需8W,无人机巡检系统落地 AI 低空智慧城市!可源码交付
  • WSL 安装 Ubuntu
  • HBase的异步WAL性能优化:RingBuffer的奥秘
  • 光猫、路由器和交换机
  • DuoPlus支持导入文件批量配置云手机参数,还优化了批量操作和搜索功能!