# 公式解説よりZ algorithm # suffix array # https://qiita.com/flare/items/20439a1db54b367eea70 # stingは文字列すべて、suffixは接尾辞、prefixは接頭辞 # たとえばstring=bananaのとき、 # suffixは、banana, anana, nana, ana, na, a # prefixは、banana, banan, bana, ban, ba, b # suffix arrayは文字列のすべてのsuffixを辞書順でソートし,その開始位置を保持した配列 # 文字列T中に出現する部分文字列は,その出現位置を開始位置とするTのsuffixのprefix # よって、文字列にあるパターンが存在するかどうかのチェックは、 # パターンPをprefixとしてもつようなTのsuffixの探索となる # たとえば、S = 'abca' のsuffix array # (index, suffix) = (0, abca), (1, bca), (2, ca), (3, a) # 辞書順ソートして、 (3, a), (0, abca), (1, bca), (2, ca) # suffix array = [3, 0, 1, 2] # LCP array, Longest Common Prefix array # suffix arrayの隣同士の文字列のprefix共通文字数の配列、つまり文字数-1の長さになる # たとえばS = 'banana' # suffix array = (5, a), (3, ana), (1, anana), (0, banana), (4, na), (2, nana) # LCP array = (1 for a), (3 for ana), (0 for none), (0 for none), (2 for na) # LCP array = [1, 3, 0, 0, 2] # https://blog.shibayu36.org/entry/2017/01/06/103956 # Zアルゴリズム # 「文字列Sを0番目からとi番目から同時に見ていった時の文字一致数」を記録した配列 # たとえば文字列momomosumomosu (桃もスモモ酢) # 0字目からと0字目からの最大一致数は全数である14 # 0字目からと1字目から(omomo---)の最大一致数は0 # 0字目からと2字目から(momo---)の最大一致数は4 # 0字目からと3字目から(omosu---)の最大一致数は0 # string.z_algorithm('momomosumomosu') # [14, 0, 4, 0, 2, 0, 0, 0, 4, 0, 2, 0, 0, 0] # https://scrapbox.io/pocala-kyopro/Z_algorithm#5da262b94a4dd500007f6fb2 # https://qiita.com/Pro_ktmr/items/16904c9570aa0953bf05 # suffix array, prefix array, z algorithm # ACL for Python # https://github.com/shakayami/ACL-for-python/blob/master/string.py # https://github.com/shakayami/ACL-for-python/wiki/string class string: def sa_is(s,upper): n=len(s) if n==0: return [] if n==1: return [0] if n==2: if (s[0]=1 and not(ls[v-1]): sa[buf[s[v-1]]]=v-1 buf[s[v-1]]+=1 buf=sum_l[:] for i in range(n-1,-1,-1): v=sa[i] if v>=1 and ls[v-1]: buf[s[v-1]+1]-=1 sa[buf[s[v-1]+1]]=v-1 lms_map=[-1]*(n+1) m=0 for i in range(1,n): if not(ls[i-1]) and ls[i]: lms_map[i]=m m+=1 lms=[] for i in range(1,n): if not(ls[i-1]) and ls[i]: lms.append(i) induce(lms) if m: sorted_lms=[] for v in sa: if lms_map[v]!=-1: sorted_lms.append(v) rec_s=[0]*m rec_upper=0 rec_s[lms_map[sorted_lms[0]]]=0 for i in range(1,m): l=sorted_lms[i-1] r=sorted_lms[i] end_l=lms[lms_map[l]+1] if (lms_map[l]+1=1 rnk=[0]*n for i in range(n): rnk[sa[i]]=i lcp=[0]*(n-1) h=0 for i in range(n): if h>0: h-=1 if rnk[i]==0: continue j=sa[rnk[i]-1] while(j+h= i: if i < N-i: ans += 1 elif 0 < ZA[i] < i: if i+ZA[i] < N and S[ZA[i]] < S[i+ZA[i]]: ans += 1 #print('i', i, 'ZA[i]', ZA[i], 'ans', ans) print(ans)