题意:
给出大小分别为 n n n 和 m m m 的数组 a 、 b a、b a、b,对于 b b b中的每个元素 b j b_j bj ,问 a 1 + b j , a 2 + b j , … , a n + b j a_1 + b_j, a_2 + b_j, \ldots, a_n + b_j a1+bj,a2+bj,…,an+bj 的GCD是多少,其中 1 ≤ n , m ≤ 2 ⋅ 1 0 5 1 \leq n, m \leq 2 \cdot 10^5 1≤n,m≤2⋅105, 1 ≤ a i ≤ 1 0 18 1 \leq a_i \leq 10^{18} 1≤ai≤1018, 1 ≤ b j ≤ 1 0 18 1 \leq b_j \leq 10^{18} 1≤bj≤1018。
思路:
- 除了欧几里得算法求GCD外,还有一种方法可以求GCD,不过速度较慢(最坏会退化为 O ( n ) O(n) O(n)),那就是九章算术 · 更相减损术:对于 a a a 大于等于 b b b, g c d ( a , b ) = g c d ( b , a − b ) = g c d ( a , a − b ) gcd(a, b) = gcd(b, a - b) = gcd(a, a - b) gcd(a,b)=gcd(b,a−b)=gcd(a,a−b), g c d ( 2 a , 2 b ) = 2 g c d ( a , b ) gcd(2a, 2b) = 2gcd(a, b) gcd(2a,2b)=2gcd(a,b)。证明: 对于 a, b 的任意公约数d,因为 d ∣ a , d ∣ b d|a, d|b d∣a,d∣b,所以 d ∣ ( a − b ) d | (a - b) d∣(a−b), 因此 d d d 也是 b , a − b b, a - b b,a−b 的公约数。反之亦成立。故 a, b 的公约数集合与 b , a − b b, a - b b,a−b 的公约数集合相同,于是他们的最大公约数也相等。对于 a , a − b a, a - b a,a−b 同理。
- 通过观察式子 a 1 + b j , a 2 + b j , … , a n + b j a_1 + b_j, a_2 + b_j, \ldots, a_n + b_j a1+bj,a2+bj,…,an+bj ,我们可以发现,他们都包含 b j b_j bj,而题目又要求它们的GCD,这很容易让我们想到更相减损术,即对于式子: a 1 + b j , a 2 + b j , … , a n + b j a_1 + b_j, a_2 + b_j, \ldots, a_n + b_j a1+bj,a2+bj,…,an+bj,如果第一项与其他各项都用更相减损术求GCD,那么式子就变为: g c d ( a 1 + b j , a b s ( a 2 − a 1 ) , … , a b s ( a n − a 1 ) ) gcd(a_1 + b_j, abs(a_2 - a_1), \ldots, abs(a_n - a_1)) gcd(a1+bj,abs(a2−a1),…,abs(an−a1)),由此可见,对于每一个 b j b_j bj 来说, g c d ( a 1 + b j , a b s ( a 2 − a 1 ) , … , a b s ( a n − a 1 ) ) gcd(a_1 + b_j, abs(a_2 - a_1), \ldots, abs(a_n - a_1)) gcd(a1+bj,abs(a2−a1),…,abs(an−a1)) 中不同的只有 b j b_j bj ,即我们可以首先求出 g = g c d ( a b s ( a 2 − a 1 ) , … , a b s ( a n − a 1 ) ) g = gcd(abs(a_2 - a_1), \ldots, abs(a_n - a_1)) g=gcd(abs(a2−a1),…,abs(an−a1)),然后对于每一个 b j b_j bj , g c d ( a 1 + b j , g ) gcd(a_1 + b_j, g) gcd(a1+bj,g) 即是答案。
- 注: 0 0 0 与任何数 x x x 的最大公约数就是 x x x 本身。
AC Codes:
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
//#include <unordered_set>
//#include <unordered_map>
#include <deque>
#include <list>
#include <iomanip>
#include <algorithm>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
//#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
//cout << fixed << setprecision(2);
//cout << setw(2);
const int N = 2e5 + 6, M = 1e9 + 7, INF = 0x3f3f3f3f;
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
int main() {
//freopen("/Users/xumingfei/Desktop/ACM/test.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
vector<ll> a(n), b(m);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
for (int i = 0; i < m; i++) {
cin >> b[i];
}
ll g = 0;
for (int i = 1; i < n; i++) {
g = gcd(g, abs(a[i] - a[0]));
}
for (int i = 0; i < m; i++) {
cout << gcd(a[0] + b[i], g) << " \n"[i == m - 1];
}
return 0;
}