Day 122-Q3 — Z-algorithm応用(文字列の最小周期判定)

2026-08-14 赤色 Master / Phase 8+ ★★★★★★★★★ 文字列アルゴリズム・O(N)

問題

長さ $N$ の文字列 $S$ が与えられる。正整数 $p$ が「$S$ の周期」であるとは、$0 \le i < N-p$ を満たすすべての $i$ について $S_i=S_{i+p}$ が成り立つことをいう。$S$ の最小の周期 $p$ を求め、さらに $N$ が $p$ の整数倍であるか(=長さ $p$ のブロックをちょうど $N/p$ 回繰り返した文字列か)を判定せよ。

入力形式

S

制約

$1 \le |S| \le 2\times10^5$
$S$ は英小文字のみ

入出力例

入力例1

abcabcabca

出力例1

3
No

入力例2

ababab

出力例2

2
Yes

概念図: Z配列と周期の関係

S = "abcabcabca" (N=10) S : abc abc abc a S[3:] : abc abc a Z[3]=7 = N-3 → p=3 は周期条件を満たす 条件: Z[p] >= N - p を満たす最小の p が最小周期 N=10, p=3 → 10%3=1≠0 なので最後のブロックは 'a' だけの半端(完全周期ではない = No) "ababab" なら p=2, N=6 → 6%2=0(Yes・完全に "ab" を3回繰り返し) 最小周期はO(N)のZ配列構築 + O(N)の線形探索でまとめて求まる

ヒント(段階的開示)

ヒント1: 方向性
定義通りにp=1,2,3,...の順に「本当に周期か」を毎回O(N)で確かめると全体O(N^2)になり間に合わない。文字列の「自分自身と、自分をずらしたものとの一致度」を高速に測る道具が使えないか、という視点で考える。
ヒント2: アプローチ
Z配列Z[i](Sと、i文字目から始まる接尾辞との最長共通接頭辞長)を思い出そう。pが周期であることは「接尾辞S[p:]がSの接頭辞と、残り長さN-p文字ぶん完全に一致する」ことを意味するので、Z[p]>=N-pという条件そのものになる。p=1から順にこれを満たす最初のpを探せば最小周期。
ヒント3: 誘導(コード骨格)
z = z_function(S)  # 標準的なZ配列構築
period = N
for p in range(1, N):
    if z[p] >= N - p:
        period = p
        break
is_full = (N % period == 0)

模範解答 (Python)

import sys

def solve():
    s = sys.stdin.readline().strip()
    n = len(s)

    z = [0] * n
    if n > 0:
        z[0] = n
        l, r = 0, 0
        for i in range(1, n):
            if i < r:
                z[i] = min(r - i, z[i - l])
            while i + z[i] < n and s[z[i]] == s[i + z[i]]:
                z[i] += 1
            if i + z[i] > r:
                l, r = i, i + z[i]

    period = n
    for p in range(1, n):
        if z[p] >= n - p:
            period = p
            break

    print(period)
    print("Yes" if n % period == 0 else "No")

solve()
計算量: Z配列構築O(N)+線形探索O(N)で全体O(N)。n=1〜30のランダム文字列3000通りに対しブルートフォース(全p試し割り)と本実装の出力を突き合わせて全一致を確認済み。

Step-by-Step 解説

1Z配列の定義の再確認
Z[i]は「S全体」と「Sをi文字目から見た接尾辞」の最長共通接頭辞の長さ。
2周期条件とZ配列の関係
pが周期であることは「S[p:]の先頭N-p文字がSの先頭N-p文字と完全一致する」ことと同値で、まさにZ[p]>=N-pという条件になる。
3最小周期の探索
p=1から順にZ[p]>=N-pを満たす最初のpを探す。見つからなければS自身(p=N)が唯一の周期。
4完全周期性の判定
最小周期pが求まったあと、Nがpの倍数かどうかで「ちょうど整数個のブロックの繰り返しか」を判定できる。
5計算量
Z配列の構築は尺取り法的な考え方によりO(N)、最小周期の探索もO(N)の線形走査なので全体O(N)。

よくあるミス

ミス原因正しい書き方
p=Nを候補から外して探索してしまうループ範囲をrange(1,n)にしたあと見つからない場合の処理を忘れる見つからなければperiod=nのままにする
周期条件をz[p]==N-pの等号で判定する「ちょうど一致」だと誤解するZ[p]がそれ以上大きくなることもあるので>=で判定する
KMPの失敗関数の考え方と混同する両者とも周期を扱うが定義対象が異なる本問はZ配列ベースの最小pを線形探索で素直に解く
Yes/Noの判定を逆に書く条件の意味を取り違えるN mod p = 0 が完全周期(Yes)であることを確認する

次のステップ

  • 発展: 文字列の全プレフィックスそれぞれについて最小周期を求める問題にも同じZ配列(あるいはKMPの失敗関数)が使える。
  • 次回予告: 木上のナップサック(依存関係付き部分木選択・O(NK)マージ)

自己評価

自分の回答

気づき・メモ