Codeforces Round #694 (Div. 2) C. Row GCD【GCD | 更相减损术】

题意:

给出大小分别为 n n n m m m 的数组 a 、 b a、b ab,对于 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 1n,m2105, 1 ≤ a i ≤ 1 0 18 1 \leq a_i \leq 10^{18} 1ai1018, 1 ≤ b j ≤ 1 0 18 1 \leq b_j \leq 10^{18} 1bj1018


思路:

  1. 除了欧几里得算法求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,ab)=gcd(a,ab) 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 da,db,所以 d ∣ ( a − b ) d | (a - b) d(ab), 因此 d d d 也是 b , a − b b, a - b b,ab 的公约数。反之亦成立。故 a, b 的公约数集合与 b , a − b b, a - b b,ab 的公约数集合相同,于是他们的最大公约数也相等。对于 a , a − b a, a - b a,ab 同理。
  2. 通过观察式子 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(a2a1),,abs(ana1)),由此可见,对于每一个 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(a2a1),,abs(ana1)) 中不同的只有 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(a2a1),,abs(ana1)),然后对于每一个 b j b_j bj g c d ( a 1 + b j , g ) gcd(a_1 + b_j, g) gcd(a1+bj,g) 即是答案。
  3. 注: 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值