#MMA Contest 015 - K Make a Sequence #リジャッジでTLEになっていたので(は?) リベンジ #static Li Chao Tree class Li_Chao_Tree: def __init__(self, X_list): #X_list: 線分追加・最小値計算で使用する、すべてのx座標 #_X[i] = x, _D[x] = i x座標とLi Chao Tree上のノードを対応 #_L[i] = (a, b): 区間の最大値候補たり得る線分 y = ax + b #_S[i] = (Lt, mid, Rt): ノードの区間(index表記) [X[Lt], X[Rt]]の閉区間が対象 self._inf = inf = 4 * 10 ** 18 X_list = sorted(set(X_list + [inf])) self._N = N = len(X_list) self._logN = logN = (N - 1).bit_length() self._size = size = 1 << logN self._X = X = X_list + [inf] * (size - N) self._D = D = {x: i for i, x in enumerate(X_list)} self._L = L = [None] * 2 * size self._S = S = [None] * size + [(i, i, i) for i in range(size)] for i in range(size - 1, 0, -1): S[i] = (S[i << 1][0], S[i << 1 | 1][0], S[i << 1 | 1][2]) def _f(self, line, x): return line[0] * x + line[1] def _add_line(self, line, i): #ノードi(と、その子)に線分を追加 Q = [(i, line)] while Q: i, line = Q.pop() if self._L[i] == None: self._L[i] = line continue Lt, mid, Rt = self._S[i] xL, xM, xR = self._X[Lt], self._X[mid], self._X[Rt] hL = self._f(line, xL) < self._f(self._L[i], xL) hM = self._f(line, xM) < self._f(self._L[i], xM) hR = self._f(line, xR) < self._f(self._L[i], xR) if hL == hR == True: self._L[i] = line continue if hL == hR == False: continue if hM == True: self._L[i], line = line, self._L[i] if hL != hM: Q.append((i << 1, line)) else: Q.append((i << 1 | 1, line)) def add_line(self, line, x_Lt = None, x_Rt = None): #半開区間[x_Lt, x_Rt)に線分追加 if x_Lt == x_Rt == None: self._add_line(line, 1) return Lt = self._D[x_Lt] if x_Lt != None else 0 Rt = self._D[x_Rt] if x_Rt != None else self._D[self._inf] Lt, Rt = Lt + self._size, Rt + self._size while Lt < Rt: if Lt & 1: self._add_line(line, Lt) Lt += 1 if Rt & 1: Rt -= 1 self._add_line(line, Rt) Lt >>= 1 Rt >>= 1 def fold(self, x): #座標xの最小値を計算 i = self._D[x] + self._size ans = self._inf while i > 0: if self._L[i]: ans = min(ans, self._f(self._L[i], x)) i >>= 1 return ans #Z-algorithm TとS[i:]のLCP判定は、T+'$'+S のようにSに出ない文字を挟んで実行するとよい #Reference: https://tjkendev.github.io/procon-library/python/string/z-algorithm.html def Z_algorithm(S): #SとS[i:]の最長共通接頭辞を求める N=len(S); A=[0]*N; i,j=1,0; A[0]=L=N while ik 10 ** 18 or k == 0: continue LCT.add_line((C[i], b - C[i] * i), i + 1, min(M, i + k) + 1) #答えを出力 ans = LCT.fold(M) print(ans if ans < 10 ** 18 else -1)