ARC050 C - LCM 111
解法
1 が A 桁続いたものと,1 が B 桁続いたものの最大公約数 G は,1 が gcd(A, B) 桁続いたものになる.
例えば 111111 (A = 6) と 1111 (B = 4) の最大公約数は,1 が gcd(6, 4) = 2桁続いたもの.
これは,
111111 = 1111 * 100 + 11
11 = 11 * 1 + 0
のようにユークリッド互除法を適用していくと,1 が並んだものがどんどん小さくなっていく.この桁数が,gcd(A, B) に対応する.
あとは A * B / G を考えるだけなので,A,B / G がどうなるか考えば十分.
ここで 1 が並んだ数は
a(k+1) = 10a(k) + 1, a(1) = 1
つまり
a(k+2) = 11a(k+1) - 10a(k)
となる数列と考えられるので,これは行列累乗で求められる.これで A は求まった.
次に,B / G を考える.これは 1000100010001...1 のような形をしていることがわかる.1 が現れる間隔が,G に対応しているので,これは
b(k+1) = 10^G b(k) + 1, b(1) = 1
という数列,つまり
b(k+2) = (10^G + 1)b(k+1) - 10^G b(k)
という数列で表される.
B はこれの B / D 項なので,同様に行列累乗で求める.
ソースコード
#include <bits/stdc++.h> using namespace std; // matrix は長いので略 int main() { ll A, B, M; cin >> A >> B >> M; ll g = __gcd(A, B); vector<ll> b1 = {11, 1}; vector<ll> b2(2); b2[0] = modpow(10, g, M) + 1; b2[1] = 1; auto C = make_matrix<ll>(2, 2); C[0][0] = 11; C[0][1] = -10 + M; C[1][0] = 1; C = modpow(C, A - 1, M); auto C2 = make_matrix<ll>(2, 2); C2[0][0] = modpow(10, g, M) + 1; C2[0][1] = -modpow(10, g, M) + M; C2[1][0] = 1; C2 = modpow(C2, B / g - 1, M); ll x = modmul(C, b1, M)[1]; ll y = modmul(C2, b2, M)[1]; cout << (x * y) % M << endl; }
感想
行列累乗じゃないコードのほうがスッキリしてた.
1111 ... を等比数列みたいに捉えるのに時間がかかってしまった.