公式
A - 歌詞検索 / Lyrics Search 解説 by admin 印刷ページ
GPT 5.2 High概要
各歌詞文字列に含まれる部分文字列 tanabata の出現回数(重なりも含む)を数え、最も回数が多い曲の番号(同率なら最小の番号)を求めます。
考察
- 求めたい「夏らしさスコア」は、文字列中に 部分文字列
tanabataが何回現れるかです。 - ここで重要なのは 出現が重なる場合も数える点です。
例えば一般に、文字列"aaaa"に"aa"は位置 0,1,2 から始まるので 3 回出現します。
本問題でも同様に、見つけた位置の次(+1)から再検索する必要があります。 - 素朴に「全ての位置から長さ 8 を切り出して一致判定」しても、
tanabataの長さは 8 で固定なので
合計文字数が最大でも \(10^6\) なら十分間に合います(\(8 \times 10^6\) 程度)。 - 提示コードでは Python の
str.findを使い、次のように数えています:find(pat, start)でstart以降の最初の出現位置を得る- 見つかったら回数を増やし、
start = pos + 1として 1 文字だけ進めて再検索(重なり対応)
さらに、最大スコアの曲が複数あるときは番号最小を選ぶので、
- cnt > best_score のときのみ更新(>= にしない)
とすることで、同点なら先に見つかった(=番号が小さい)曲が保持されます。
アルゴリズム
- パターン
pat = "tanabata"を用意する。 - 各曲 \(i=1..N\) について以下を行う:
cnt = 0,start = 0とする。- ループで
pos = S_i.find(pat, start)を実行する。pos == -1なら見つからないので終了。- 見つかったら
cnt += 1、次は重なりを許すためstart = pos + 1とする。
cntがこれまでの最大値より大きければ、最大値と答えの番号を更新する。
- 最終的に保持している番号を出力する。
計算量
- 時間計算量: \(O\!\left(\sum_{i=1}^{N} |S_i|\right)\)(
tanabataの長さが定数で、各文字列を実質的に線形に処理できるため) - 空間計算量: \(O(1)\)(入力文字列以外に大きな追加領域を使わない)
実装のポイント
重なりを数えるため、次の探索開始位置を
pos + len(pat)ではなくpos + 1にする。同点の場合は最小の番号にしたいので、更新条件は
cnt > best_scoreにする(>=にしない)。入力が大きいので
sys.stdin.buffer.readlineを使って高速に読み込む。ソースコード
import sys
def main():
input = sys.stdin.buffer.readline
N_line = input()
if not N_line:
return
N = int(N_line)
pat = "tanabata"
best_idx = 1
best_score = -1
for i in range(1, N + 1):
s = input().decode().strip()
cnt = 0
start = 0
while True:
pos = s.find(pat, start)
if pos == -1:
break
cnt += 1
start = pos + 1 # allow overlap
if cnt > best_score:
best_score = cnt
best_idx = i
sys.stdout.write(str(best_idx))
if __name__ == "__main__":
main()
この解説は gpt-5.2-high によって生成されました。
投稿日時:
最終更新: