Hewlaの競プロ記

競プロ記です。

AtCoder AGC028 A - Two Abbreviations (300点)

ちょっとだけ迷走した。
AtCoder Grand Contest 028のA。

概要

問題URL
A - Two Abbreviations

二つの文字列S(長さN), T(長さM)が与えられる。
文字列X(長さL)について、

  • LN, Mのどちらでも割り切れる
  • X1, \frac L N+1, 2\times {\frac L N}+1, ..., (N-1)\times\frac L N+1番目だけ抽出してくるとSと同じ
  • X1, \frac L M+1, 2\times {\frac L M}+1, ..., (N-1)\times\frac L M+1番目だけ抽出してくるとTと同じ

となる文字列Xが存在するならばそのうちで最短のものの長さを、存在しないならば-1を出力せよ。

制約

1\leq N, M\leq10^5

解説

STを両方ともいい感じに同じ長さに引き伸ばして、場所がかぶったところの文字が全部同じになったらOKという感じです。2\times {\frac L N}+1とか言っていてわかりづらいですが、0-basedで考えると\frac L Nの整数倍というだけなので簡単です。
f:id:hewla:20181014000304p:plain
入出力例3の様子を画像にしてみました。見づらくてすみません>_<
かぶっているところが赤く塗られていますが、その部分が上の文字列Sとしたの文字列Tで同じです。このように、場所のかぶったところが同じならその長さは条件を満たします。

まず、LN, Mのどちらでも割り切れるので、Lは一番小さくてN, Mの最小公倍数(LCM(N, M))で、必ずLCM(N, M)の倍数です。この時場所がかぶっている文字は、N, Mの最大公約数をg = GCD(N, M)とすると、

  • 文字列SではS[ \frac {iN} g ], 文字列TではT[ \frac {iM} g ] (i = 0, 1, 2, ..., g-1)

です。
さらに考えると、こうしてできた文字列で場所がかぶっている文字は、この文字列をいくら引きのばしても場所がかぶったままです。よって、L = LCM(N, M)でうまくいかない場合は、これを満たす文字列は存在しないということになります。

したがって、i = 0, 1, 2, ..., g-1について、S[ \frac {iN} g ] == T[ \frac {iM} g ] を確かめるだけでよいことになります。

最大公約数についてはユークリッドの互除法が高速で便利です。コピペで使うライブラリを作ったので、リンクを貼っておきます。一応実装したことない人は一度やってみることをお勧めします。GitHubの扱いは不慣れですので何か間違ってたらごめんなさい。
Cpp_ComProLib/gcd at master · hewlae/Cpp_ComProLib · GitHub
最小公倍数は最大公約数ともとの2数N, Mから簡単に求められ、その値はLCM(N, M) = \frac {NM}{GCD(N, M)}です。

なにか間違っている点や質問などがあったらTwitterやコメントなどで教えてください。

感想

GCDやLCMにはすぐにたどり着きました(そこはいつも得意)が、いくら引きのばしても場所がかぶるやつはかぶるということに気づくまでにちょっとかかり、迷走してしまいました。13分で解けたのはラッキー