けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

AtCoder ABC 109 C - Skip (茶色, 300 点)

一瞬「訪れる順番によって状況が変わらないか...」と不安になるかもな問題だけど、よく考えたら訪れる順番を考える必要もない。ソートしても OK だけどソートする必要はなかった。

問題へのリンク

問題概要

 N 個の点が一直線上に並んでいて、各頂点の座標は  x_1, x_2, ..., x_N である。今、 X から出発してすべての頂点に行くことを考える。以下の条件を満たすような最大の整数  D を求めよ:

  •  X から出発して以下の操作を好きなだけ行い、各座標に一度以上ピッタリと止まることが可能である
    • 現在地を  x として  x+D に移動する
    • 現在地を  x として  x-D に移動する

制約

  •  1 \le N \le 10^{5}

考えたこと

とりあえず  X で出発という条件を

  •  0 から出発して  x_1 - X,  x_2 - X, ...,  x_N - X をめぐる

という風にしても特に変わらないので、そうする。こうすると、何度移動を繰り返しても、

  • たどり着く場所の座標は必ず  D の倍数
  • 逆に  D の倍数の地点には必ずたどり着ける

ということがわかる。したがって必要十分条件は、

  •  D x_1 - X の約数
  • ...
  •  D x_N - X の約数

となること、すなわち、

  •  D {\rm GCD}(x_1 - X, \dots, x_N - X) の約数

となることがわかる。よって最大値は  D = {\rm GCD}(x_1 - X, \dots, x_N - X) になる。

#include <iostream>
#include <vector>
using namespace std;

long long GCD(long long a, long long b) {
    if (b == 0) return a;
    else return GCD(b, a % b);
}

int main() {
    int N; long long X;
    cin >> N >> X;
    vector<long long> x(N); for (int i = 0; i < N; ++i) cin >> x[i], x[i] -= X;
    long long g = abs(x[0]);
    for (int i = 0; i < N; ++i) g = GCD(g, abs(x[i]));
    cout << g << endl;
}