dkl9 commited on 2025-202 20:54:00
Showing 2 changed files, with 19 additions and 17 deletions.
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
from collections import defaultdict |
| 2 | 2 |
import re |
| 3 | 3 |
import sys |
| 4 |
+import time |
|
| 4 | 5 |
from typing import Generator |
| 5 | 6 |
|
| 6 | 7 |
def minima(options, key): |
| ... | ... |
@@ -15,15 +16,18 @@ def minima(options, key): |
| 15 | 16 |
result.add(o) |
| 16 | 17 |
return result |
| 17 | 18 |
|
| 18 |
-def cost(token: str, child: "Trie") -> tuple: |
|
| 19 |
- weight = child.deep_weight() |
|
| 20 |
- return child.deep_usage() / weight, -weight, len(token), token |
|
| 19 |
+def cost(token_child: tuple[str, "Trie"]) -> tuple: |
|
| 20 |
+ token, child = token_child |
|
| 21 |
+ weight = child.deep_weight |
|
| 22 |
+ return child.deep_usage / weight, -weight, len(token), token |
|
| 21 | 23 |
|
| 22 | 24 |
class Trie: |
| 23 | 25 |
def __init__(self, weight: int = 0): |
| 24 | 26 |
self.children: defaultdict[str, Trie] = defaultdict(Trie) |
| 25 | 27 |
self.weight: int = weight |
| 28 |
+ self.deep_weight: int = weight |
|
| 26 | 29 |
self.usage: int = 0 |
| 30 |
+ self.deep_usage: int = 0 |
|
| 27 | 31 |
|
| 28 | 32 |
def __str__(self) -> str: |
| 29 | 33 |
s = f"[{self.usage}/{self.weight}]"
|
| ... | ... |
@@ -32,25 +36,17 @@ class Trie: |
| 32 | 36 |
return s |
| 33 | 37 |
|
| 34 | 38 |
def add(self, word: list[str], weight: int = 1): |
| 39 |
+ self.deep_weight += weight |
|
| 35 | 40 |
if word: |
| 36 | 41 |
self.children[word[0]].add(word[1:], weight) |
| 37 | 42 |
else: |
| 38 | 43 |
self.weight += weight |
| 39 | 44 |
|
| 40 |
- def deep_weight(self) -> int: |
|
| 41 |
- return self.weight + sum(c.deep_weight() for c in self.children.values()) |
|
| 42 |
- |
|
| 43 |
- def deep_usage(self) -> int: |
|
| 44 |
- return self.usage + sum(c.deep_usage() for c in self.children.values()) |
|
| 45 |
- |
|
| 46 | 45 |
def best(self) -> tuple[list[str], "Trie"]: |
| 47 | 46 |
if self.weight > self.usage: |
| 48 | 47 |
return [], self |
| 49 | 48 |
elif self.children: |
| 50 |
- token, child = min( |
|
| 51 |
- self.children.items(), |
|
| 52 |
- key=lambda kc: cost(*kc) |
|
| 53 |
- ) |
|
| 49 |
+ token, child = min(self.children.items(), key=cost) |
|
| 54 | 50 |
suffix, leaf = child.best() |
| 55 | 51 |
if not leaf: |
| 56 | 52 |
return None, None |
| ... | ... |
@@ -58,7 +54,11 @@ class Trie: |
| 58 | 54 |
else: |
| 59 | 55 |
return None, None |
| 60 | 56 |
|
| 61 |
- def use(self): |
|
| 57 |
+ def use(self, word: list[str]): |
|
| 58 |
+ self.deep_usage += 1 |
|
| 59 |
+ if word: |
|
| 60 |
+ self.children[word[0]].use(word[1:]) |
|
| 61 |
+ else: |
|
| 62 | 62 |
assert self.usage < self.weight |
| 63 | 63 |
self.usage += 1 |
| 64 | 64 |
|
| ... | ... |
@@ -66,16 +66,16 @@ class Trie: |
| 66 | 66 |
while True: |
| 67 | 67 |
tokens, leaf = self.best() |
| 68 | 68 |
if not leaf: |
| 69 |
- assert self.deep_usage() == self.deep_weight() |
|
| 69 |
+ assert self.deep_usage == self.deep_weight |
|
| 70 | 70 |
break |
| 71 | 71 |
yield tokens |
| 72 |
- leaf.use() |
|
| 72 |
+ self.use(tokens) |
|
| 73 | 73 |
|
| 74 | 74 |
re_flags = re.MULTILINE | re.DOTALL |
| 75 | 75 |
token_pattern = "[-_ \t]*[^-_\\s]+" |
| 76 | 76 |
entry_pattern = re.compile(f"({token_pattern})+", re_flags)
|
| 77 | 77 |
token_pattern = re.compile(token_pattern, re_flags) |
| 78 |
-words = (re.findall(token_pattern, m.group(0)) for m in re.finditer(entry_pattern, sys.stdin.read())) |
|
| 78 |
+words = [re.findall(token_pattern, m.group(0)) for m in re.finditer(entry_pattern, sys.stdin.read())] |
|
| 79 | 79 |
t = Trie() |
| 80 | 80 |
for w in words: |
| 81 | 81 |
t.add(w) |
| 82 | 82 |