結果

問題 No.430 文字列検索
ユーザー むらためむらため
提出日時 2019-10-04 06:00:43
言語 Nim
(2.0.2)
結果
RE  
実行時間 -
コード長 6,801 bytes
コンパイル時間 3,494 ms
コンパイル使用メモリ 71,204 KB
実行使用メモリ 453,264 KB
最終ジャッジ日時 2024-04-14 09:47:51
合計ジャッジ時間 7,100 ms
ジャッジサーバーID
(参考情報)
judge4 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
13,752 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]

ソースコード

diff #

# 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
0