ABC 135 F - Strings of Eternity【Python】

問題はこちら

解説を見ながらなんとか実装した。

KMPは文字列検索を線形時間で終わらせるアルゴリズムで以前作っておいたものを使った。解説はwikipedia参照。最長経路の計算ではループもあり得るのでループ検出をする必要がある。

有向グラフのループ検出をするアルゴリズムを忘れかけていたので軽くメモしておく。

dfsで全探索するときに、訪問したことを示すvisitedというフラグと、処理が完了したことを示すfinishedというフラグを用意して、それぞれ行きがけと帰りがけにチェックする。finishしてないのにvisitedがTrueになっている頂点に訪れているということはループが存在するということなのでこれを使ってループ検出できる。

import sys
sys.setrecursionlimit(10**9)
read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines

class KMP():
   def __init__(self, pattern):
       n = len(pattern)
       table = [0]*(n + 1)
       table[0], table[1] = -1, 0
       i, j = 2, 0
       while i <= n:
           if pattern[i - 1] == pattern[j]:
               table[i] = j + 1
               i += 1; j += 1
           elif j > 0:
               j = table[j]
           else:
               table[i] = 0
               i += 1
       self.size = n
       self.pattern = pattern
       self.table = table
   
   def search(self, text):
       l = len(text)
       n = self.size
       table = self.table
       pattern = self.pattern
       m, i = 0, 0
       ret = []
       while m + i < l:
           if pattern[i] == text[m + i]:
               i += 1
               if i == n:
                   ret.append(m)
                   m += i - table[i]
                   i = table[i]
           else:
               m += i - table[i]
               if i > 0:
                   i = table[i]
       return ret
       
def main():
   s = readline().strip()
   t = readline().strip()
   ls, lt = len(s), len(t)
   times = lt // ls + 2
   S_inf = s * times
   
   kmp = KMP(t)
   conn = [[] for _ in range(ls)]
   match = kmp.search(S_inf)
   for i in match:
       if i < ls:
           conn[i].append((i + lt) % ls)
           
   dp = [0]*ls
   visited = [False]*ls
   finished = [False]*ls
   
   def dfs(x):
       visited[x] = True
       for y in conn[x]:
           if visited[y]:
               if finished[y]:
                   dp[x] = max(dp[x], dp[y])
                   continue
               else:
                   print(-1)
                   sys.exit()
           dfs(y)
           dp[x] = max(dp[x], dp[y])
       dp[x] += 1
       finished[x] = True
       
   for x in range(ls):
       if finished[x]:
           continue
       dfs(x)
       
   print(max(dp) - 1)
   
if __name__ == "__main__":
  main()



この記事が気に入ったらサポートをしてみませんか?