結果
問題 | No.430 文字列検索 |
ユーザー | むらため |
提出日時 | 2019-10-04 06:00:43 |
言語 | Nim (2.0.2) |
結果 |
RE
|
実行時間 | - |
コード長 | 6,801 bytes |
コンパイル時間 | 3,337 ms |
コンパイル使用メモリ | 71,040 KB |
実行使用メモリ | 462,284 KB |
最終ジャッジ日時 | 2024-11-10 00:35:34 |
合計ジャッジ時間 | 6,768 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
10,496 KB |
testcase_01 | RE | - |
testcase_02 | TLE | - |
testcase_03 | -- | - |
testcase_04 | -- | - |
testcase_05 | -- | - |
testcase_06 | -- | - |
testcase_07 | -- | - |
testcase_08 | -- | - |
testcase_09 | -- | - |
testcase_10 | -- | - |
testcase_11 | -- | - |
testcase_12 | -- | - |
testcase_13 | -- | - |
testcase_14 | -- | - |
testcase_15 | -- | - |
testcase_16 | -- | - |
testcase_17 | -- | - |
コンパイルメッセージ
/home/judge/data/code/Main.nim(2, 8) Warning: imported and not used: 'sequtils' [UnusedImport] /home/judge/data/code/Main.nim(175, 8) Warning: imported and not used: 'sequtils' [UnusedImport] /home/judge/data/code/Main.nim(175, 17) Warning: imported and not used: 'algorithm' [UnusedImport] /home/judge/data/code/Main.nim(175, 27) Warning: imported and not used: 'math' [UnusedImport] /home/judge/data/code/Main.nim(175, 32) Warning: imported and not used: 'strutils' [UnusedImport] /home/judge/data/code/Main.nim(175, 41) Warning: imported and not used: 'tables' [UnusedImport] /home/judge/data/code/Main.nim(175, 48) Warning: imported and not used: 'sets' [UnusedImport]
ソースコード
# https://yukicoder.me/problems/no/430 import sequtils type PatriciaNode = ref object nexts : seq[PatriciaNode] count : int # 自身を終端とする文字列の数 countSum : int # 自身のprefixを持つ文字列の数 value : string # 念の為全部の値を持っておく.どうせ後で欲しくなるので PatriciaTree = ref object root : PatriciaNode charSize : int offset : int proc newPatriciaNode(charSize:int,value:string):PatriciaNode = new(result) result.nexts = newSeq[PatriciaNode](charSize) result.count = 1 result.countSum = 1 result.value = value proc `$`*(self:PatriciaTree):string = proc dump(node:PatriciaNode,indent:int = 0):string = if node.countSum == 0 : return "" result = "" for i in 0..<indent: result.add " " result.add node.value & "(" & $node.countSum & ", " & $node.count & ")\n" for next in node.nexts: if next != nil: result.add next.dump(indent + 1) return self.root.dump() proc newPatriciaTree*(charSize:int,offset:int):PatriciaTree = new(result) result.root = newPatriciaNode(charSize,"") result.root.count = 0 result.root.countSum = 0 result.charSize = charSize result.offset = offset proc newLowerCasePatriciaTree*():PatriciaTree = # a~z,26種 newPatriciaTree('z'.ord - 'a'.ord , 'a'.ord) proc newUpperCasePatriciaTree*():PatriciaTree = # A~Z,26種 newPatriciaTree('Z'.ord - 'A'.ord , 'A'.ord) proc newASCIIPatriciaTree*():PatriciaTree = # ASCII印字可能文字全て,94種 newPatriciaTree('~'.ord - '!'.ord, '!'.ord) proc newNumericPatriciaTree*():PatriciaTree = # 0~9,10種 newPatriciaTree('9'.ord - '0'.ord , '0'.ord) proc newBytePatriciaTree*():PatriciaTree = # 0~255,256種 newPatriciaTree(256 , 0) proc newBinaryPatriciaTree*():PatriciaTree = # 01,2種 newPatriciaTree(2 , 0) # 重複を許して追加 proc addMulti*(self:var PatriciaTree,S:string) = if S.len == 0: # ""の時 self.root.count += 1 self.root.countSum += 1 return var now = self.root var index = 0 while true: now.countSum += 1 # 既に index は該当の場所になっていると仮定 let s = S[index].ord - self.offset # 無かったので追加 if now.nexts[s] == nil: now.nexts[s] = self.charSize.newPatriciaNode(S) return # now.nexts[s] が存在する # どちらがよりふさわしいかを確かめる. let minLen = S.len.min(now.nexts[s].value.len) while true: if index >= minLen: break if now.nexts[s].value[index] != S[index]: break index += 1 # 全く同じだった if S.len == index and now.nexts[s].value.len == index: now.nexts[s].count += 1 now.nexts[s].countSum += 1 return # 相手の方が短かったので相手はただの通過点であった. if now.nexts[s].value.len == index: now = now.nexts[s] continue # 異なるので中間点を作る必要がある var common = self.charSize .newPatriciaNode(if S.len == index: S else: S[0..<index]) # 自分の方が短かったので自身を中間点とする let differentCharP = now.nexts[s].value[index].ord - self.offset let preTree = now.nexts[s] now.nexts[s] = common common.nexts[differentCharP] = preTree common.count = 0 common.countSum = preTree.countSum + 1 # そこで終了した if S.len == index: common.count += 1 return # まだまだ長さに余力があるが,prefixが違うところに来たのだった. 新しい葉を作って終了 let differentCharS = S[index].ord - self.offset if common.nexts[differentCharS] != nil: echo "このメッセージはでないはずだよ" doAssert(false) common.nexts[differentCharS] = self.charSize.newPatriciaNode(S) return # 存在確認 proc `in`*(S:string,self:PatriciaTree) :bool= if S.len == 0: return self.root.count > 0 var now = self.root var index = 0 while true: let s = S[index].ord - self.offset if now.nexts[s] == nil: return false if S.len < now.nexts[s].value.len : return false while true: if index >= now.nexts[s].value.len: break if now.nexts[s].value[index] != S[index]: break index += 1 if S.len == index and now.nexts[s].value.len == index: return now.nexts[s].count > 0 if now.nexts[s].value.len == index: now = now.nexts[s] continue return false # 追加 proc add*(self:var PatriciaTree,S:string) = if not (S in self): self.addMulti S # 構築に時間がかかるので,本当に削除はしない. # メモリが増えすぎて困る、ということがあれば削除を検討しても良い. proc delete*(self:var PatriciaTree,S:string) = if S.len == 0: if self.root.count > 0 : self.root.count -= 1 self.root.countSum -= 1 return if not (S in self): return var now = self.root var index = 0 while true: now.countSum -= 1 let s = S[index].ord - self.offset if now.nexts[s] == nil: return if S.len < now.nexts[s].value.len : return while true: if index >= now.nexts[s].value.len: break if now.nexts[s].value[index] != S[index]: break index += 1 if S.len == index and now.nexts[s].value.len == index: if now.nexts[s].count > 0: now.nexts[s].count -= 1 now.nexts[s].countSum -= 1 return if now.nexts[s].value.len == index: now = now.nexts[s] continue return # 要素数 proc len*(self:PatriciaTree):int = self.root.countSum proc countWithPrefix*(self:PatriciaTree,S:string):int = if S.len == 0: return self.root.countSum var index = 0 var now = self.root while true: if index >= S.len: return now.countSum let s = S[index].ord - self.offset if now.nexts[s] == nil: # "bcd" に "bc" みたいなノードがきた # if index == now.value.len: return now.countSum return 0 if S.len < now.nexts[s].value.len : index = now.nexts[s].value.len now = now.nexts[s] continue while true: if index >= now.nexts[s].value.len: break if now.nexts[s].value[index] != S[index]: break index += 1 now = now.nexts[s] import sequtils,algorithm,math,strutils,tables,sets template times*(n:int,body) = (for _ in 0..<n: body) template `max=`*(x,y) = x = max(x,y) template `min=`*(x,y) = x = min(x,y) proc getchar_unlocked():char {. importc:"getchar_unlocked",header: "<stdio.h>" ,discardable.} proc scan(): int = while true: let k = getchar_unlocked() if k < '0' or k > '9': return result = 10 * result + k.ord - '0'.ord let S = stdin.readLine() let m = scan() var T = newUpperCasePatriciaTree() for i in 0..<S.len: T.addMulti S[i..^1] var ans = 0 m.times: let C = stdin.readLine() ans += T.countWithPrefix(C) echo ans