"""# ### 谜题描述 The tycoon of a winery empire in Mondstadt, unmatched in every possible way. A thinker in the Knights of Favonius with an exotic appearance. This time, the brothers are dealing with a strange piece of wood marked with their names. This plank of wood can be represented as a string of n characters. Each character is either a 'D' or a 'K'. You want to make some number of cuts (possibly 0) on this string, partitioning it into several contiguous pieces, each with length at least 1. Both brothers act with dignity, so they want to split the wood as evenly as possible. They want to know the maximum number of pieces you can split the wood into such that the ratios of the number of occurrences of 'D' to the number of occurrences of 'K' in each chunk are the same. Kaeya, the curious thinker, is interested in the solution for multiple scenarios. He wants to know the answer for every prefix of the given string. Help him to solve this problem! For a string we define a ratio as a:b where 'D' appears in it a times, and 'K' appears b times. Note that a or b can equal 0, but not both. Ratios a:b and c:d are considered equal if and only if a⋅ d = b⋅ c. For example, for the string 'DDD' the ratio will be 3:0, for 'DKD' — 2:1, for 'DKK' — 1:2, and for 'KKKKDD' — 2:4. Note that the ratios of the latter two strings are equal to each other, but they are not equal to the ratios of the first two strings. Input Each test contains multiple test cases. The first line contains the number of test cases t (1 ≤ t ≤ 1000). Description of the test cases follows. The first line of each test case contains an integer n (1 ≤ n ≤ 5 ⋅ 10^5) — the length of the wood. The second line of each test case contains a string s of length n. Every character of s will be either 'D' or 'K'. It is guaranteed that the sum of n over all test cases does not exceed 5 ⋅ 10^5. Output For each test case, output n space separated integers. The i-th of these numbers should equal the answer for the prefix s_{1},s_{2},...,s_{i}. Example Input 5 3 DDK 6 DDDDDD 4 DKDK 1 D 9 DKDKDDDDK Output 1 2 1 1 2 3 4 5 6 1 1 1 2 1 1 1 1 2 1 2 1 1 3 Note For the first test case, there is no way to partition 'D' or 'DDK' into more than one block with equal ratios of numbers of 'D' and 'K', while you can split 'DD' into 'D' and 'D'. For the second test case, you can split each prefix of length i into i blocks 'D'. Here is a reference code to solve this task. You can use this to help you genereate cases or validate the solution. ```python # Enter your code here. Read input from STDIN. Print output to STDOUT# =============================================================================================== # importing some useful libraries. from __future__ import division, print_function from fractions import Fraction import sys import os from io import BytesIO, IOBase from itertools import * import bisect from heapq import * from math import ceil, floor from copy import * from collections import deque, defaultdict from collections import Counter as counter # Counter(list) return a dict with {key: count} from itertools import combinations # if a = [1,2,3] then print(list(comb(a,2))) -----> [(1, 2), (1, 3), (2, 3)] from itertools import permutations as permutate from bisect import bisect_left as bl from operator import * # If the element is already present in the list, # the left most position where element has to be inserted is returned. from bisect import bisect_right as br from bisect import bisect # If the element is already present in the list, # the right most position where element has to be inserted is returned # ============================================================================================== # fast I/O region BUFSIZE = 8192 from sys import stderr class FastIO(IOBase): newlines = 0 def __init__(self, file): self._fd = file.fileno() self.buffer = BytesIO() self.writable = \"A\" in file.mode or \"r\" not in file.mode self.write = self.buffer.write if self.writable else None def read(self): while True: b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE)) if not b: break ptr = self.buffer.tell() self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr) self.newlines = 0 return self.buffer.read() def readline(self): while self.newlines == 0: b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE)) self.newlines = b.count(b\"\n\") + (not b) ptr = self.buffer.tell() self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr) self.newlines -= 1 return self.buffer.readline() def flush(self): if self.writable: os.write(self._fd, self.buffer.getvalue()) self.buffer.truncate(0), self.buffer.seek(0) class IOWrapper(IOBase): def __init__(self, file): self.buffer = FastIO(file) self.flush = self.buffer.flush self.writable = self.buffer.writable self.write = lambda s: self.buffer.write(s.encode(\"ascii\")) self.read = lambda: self.buffer.read().decode(\"ascii\") self.readline = lambda: self.buffer.readline().decode(\"ascii\") def print(*args, **kwargs): \"\"\"Prints the values to a stream, or to sys.stdout by default.\"\"\" sep, file = kwargs.pop(\"sep\", \" \"), kwargs.pop(\"file\", sys.stdout) at_start = True for A in args: if not at_start: file.write(sep) file.write(str(A)) at_start = False file.write(kwargs.pop(\"end\", \"\n\")) if kwargs.pop(\"flush\", False): file.flush() if sys.version_info[0] < 3: sys.stdin, sys.stdout = FastIO(sys.stdin), FastIO(sys.stdout) else: sys.stdin, sys.stdout = IOWrapper(sys.stdin), IOWrapper(sys.stdout) # inp = lambda: sys.stdin.readline().rstrip(\"\r\n\") # =============================================================================================== ### START ITERATE RECURSION ### from types import GeneratorType def iterative(f, stack=[]): def wrapped_func(*args, **kwargs): if stack: return f(*args, **kwargs) to = f(*args, **kwargs) while True: if type(to) is GeneratorType: stack.append(to) to = next(to) continue stack.pop() if not stack: break to = stack[-1].send(to) return to return wrapped_func #### END ITERATE RECURSION #### ########################### # Sorted list class SortedList: def __init__(self, iterable=[], _load=200): \"\"\"Initialize sorted list instance.\"\"\" values = sorted(iterable) self._len = _len = len(values) self._load = _load self._lists = _lists = [values[start:start + _load] for start in range(0, _len, _load)] self._list_lens = [len(_list) for _list in _lists] self._mins = [_list[0] for _list in _lists] self._fen_tree = [] self._rebuild = True def _fen_build(self): \"\"\"Build a fenwick tree instance.\"\"\" self._fen_tree[:] = self._list_lens _fen_tree = self._fen_tree for start in range(len(_fen_tree)): if start | start + 1 < len(_fen_tree): _fen_tree[start | start + 1] += _fen_tree[start] self._rebuild = False def _fen_update(self, index, value): \"\"\"Update `fen_tree[index] += value`.\"\"\" if not self._rebuild: _fen_tree = self._fen_tree while index < len(_fen_tree): _fen_tree[index] += value index |= index + 1 def _fen_query(self, end): \"\"\"Return `sum(_fen_tree[:end])`.\"\"\" if self._rebuild: self._fen_build() _fen_tree = self._fen_tree A = 0 while end: A += _fen_tree[end - 1] end &= end - 1 return A def _fen_findkth(self, k): \"\"\"Return a pair of (the largest `idx` such that `sum(_fen_tree[:idx]) <= k`, `k - sum(_fen_tree[:idx])`).\"\"\" _list_lens = self._list_lens if k < _list_lens[0]: return 0, k if k >= self._len - _list_lens[-1]: return len(_list_lens) - 1, k + _list_lens[-1] - self._len if self._rebuild: self._fen_build() _fen_tree = self._fen_tree idx = -1 for d in reversed(range(len(_fen_tree).bit_length())): right_idx = idx + (1 << d) if right_idx < len(_fen_tree) and k >= _fen_tree[right_idx]: idx = right_idx k -= _fen_tree[idx] return idx + 1, k def _delete(self, pos, idx): \"\"\"Delete value at the given `(pos, idx)`.\"\"\" _lists = self._lists _mins = self._mins _list_lens = self._list_lens self._len -= 1 self._fen_update(pos, -1) del _lists[pos][idx] _list_lens[pos] -= 1 if _list_lens[pos]: _mins[pos] = _lists[pos][0] else: del _lists[pos] del _list_lens[pos] del _mins[pos] self._rebuild = True def _loc_left(self, value): \"\"\"Return an index pair that corresponds to the first position of `value` in the sorted list.\"\"\" if not self._len: return 0, 0 _lists = self._lists _mins = self._mins lo, pos = -1, len(_lists) - 1 while lo + 1 < pos: mi = (lo + pos) >> 1 if value <= _mins[mi]: pos = mi else: lo = mi if pos and value <= _lists[pos - 1][-1]: pos -= 1 _list = _lists[pos] lo, idx = -1, len(_list) while lo + 1 < idx: mi = (lo + idx) >> 1 if value <= _list[mi]: idx = mi else: lo = mi return pos, idx def _loc_right(self, value): \"\"\"Return an index pair that corresponds to the last position of `value` in the sorted list.\"\"\" if not self._len: return 0, 0 _lists = self._lists _mins = self._mins pos, hi = 0, len(_lists) while pos + 1 < hi: mi = (pos + hi) >> 1 if value < _mins[mi]: hi = mi else: pos = mi _list = _lists[pos] lo, idx = -1, len(_list) while lo + 1 < idx: mi = (lo + idx) >> 1 if value < _list[mi]: idx = mi else: lo = mi return pos, idx def add(self, value): \"\"\"Add `value` to sorted list.\"\"\" _load = self._load _lists = self._lists _mins = self._mins _list_lens = self._list_lens self._len += 1 if _lists: pos, idx = self._loc_right(value) self._fen_update(pos, 1) _list = _lists[pos] _list.insert(idx, value) _list_lens[pos] += 1 _mins[pos] = _list[0] if _load + _load < len(_list): _lists.insert(pos + 1, _list[_load:]) _list_lens.insert(pos + 1, len(_list) - _load) _mins.insert(pos + 1, _list[_load]) _list_lens[pos] = _load del _list[_load:] self._rebuild = True else: _lists.append([value]) _mins.append(value) _list_lens.append(1) self._rebuild = True def discard(self, value): \"\"\"Remove `value` from sorted list if it is a member.\"\"\" _lists = self._lists if _lists: pos, idx = self._loc_right(value) if idx and _lists[pos][idx - 1] == value: self._delete(pos, idx - 1) def remove(self, value): \"\"\"Remove `value` from sorted list; `value` must be a member.\"\"\" _len = self._len self.discard(value) if _len == self._len: raise ValueError('{0!r} not in list'.format(value)) def pop(self, index=-1): \"\"\"Remove and return value at `index` in sorted list.\"\"\" pos, idx = self._fen_findkth(self._len + index if index < 0 else index) value = self._lists[pos][idx] self._delete(pos, idx) return value def bisect_left(self, value): \"\"\"Return the first index to insert `value` in the sorted list.\"\"\" pos, idx = self._loc_left(value) return self._fen_query(pos) + idx def bisect_right(self, value): \"\"\"Return the last index to insert `value` in the sorted list.\"\"\" pos, idx = self._loc_right(value) return self._fen_query(pos) + idx def count(self, value): \"\"\"Return number of ofinansurrences of `value` in the sorted list.\"\"\" return self.bisect_right(value) - self.bisect_left(value) def __len__(self): \"\"\"Return the size of the sorted list.\"\"\" return self._len def __getitem__(self, index): \"\"\"Lookup value at `index` in sorted list.\"\"\" pos, idx = self._fen_findkth(self._len + index if index < 0 else index) return self._lists[pos][idx] def __delitem__(self, index): \"\"\"Remove value at `index` from sorted list.\"\"\" pos, idx = self._fen_findkth(self._len + index if index < 0 else index) self._delete(pos, idx) def __contains__(self, value): \"\"\"Return true if `value` is an element of the sorted list.\"\"\" _lists = self._lists if _lists: pos, idx = self._loc_left(value) return idx < len(_lists[pos]) and _lists[pos][idx] == value return False def __iter__(self): \"\"\"Return an iterator over the sorted list.\"\"\" return (value for _list in self._lists for value in _list) def __reversed__(self): \"\"\"Return a reverse iterator over the sorted list.\"\"\" return (value for _list in reversed(self._lists) for value in reversed(_list)) def __repr__(self): \"\"\"Return string representation of sorted list.\"\"\" return 'SortedList({0})'.format(list(self)) # =============================================================================================== # some shortcuts mod = 1000000007 def YES(): print(\"YES\") def NO(): print(\"NO\") def Yes(): print(\"Yes\") def No(): print(\"No\") def pow(A, B, p): res = 1 # Initialize result A = A % p # Update A if it is more , than or equal to p if (A == 0): return 0 while (B > 0): if ((B & 1) == 1): # If B is odd, multiply, A with result res = (res * A) % p B = B >> 1 # B = B/2 A = (A * A) % p return res from functools import reduce def numberOfSetBits(n): n = (n & 0x5555555555555555) + ((n & 0xAAAAAAAAAAAAAAAA) >> 1) n = (n & 0x3333333333333333) + ((n & 0xCCCCCCCCCCCCCCCC) >> 2) n = (n & 0x0F0F0F0F0F0F0F0F) + ((n & 0xF0F0F0F0F0F0F0F0) >> 4) n = (n & 0x00FF00FF00FF00FF) + ((n & 0xFF00FF00FF00FF00) >> 8) n = (n & 0x0000FFFF0000FFFF) + ((n & 0xFFFF0000FFFF0000) >> 16) n = (n & 0x00000000FFFFFFFF) + ((n & 0xFFFFFFFF00000000) >> 32) # This last & isn't strictly necessary. return n def factors(n): return set(reduce(list.__add__, ([start, n // start] for start in range(1, int(n ** 0.5) + 1) if n % start == 0))) class MergeFind: def __init__(self, n): self.parent = list(range(n)) self.size = [1] * n self.num_sets = n # self.lista = [[_] for _ in range(n)] def find(self, a): to_update = [] while a != self.parent[a]: to_update.append(a) a = self.parent[a] for b in to_update: self.parent[b] = a return self.parent[a] def merge(self, a, b): a = self.find(a) b = self.find(b) if a == b: return if self.size[a] < self.size[b]: a, b = b, a self.num_sets -= 1 self.parent[b] = a self.size[a] += self.size[b] # self.lista[a] += self.lista[b] # self.lista[b] = [] def set_size(self, a): return self.size[self.find(a)] def __len__(self): return self.num_sets def gcd(a, b): if a == b: return a while b > 0: a, b = b, a % b return a def lcm(a, b): return abs((a // gcd(a, b)) * b) inf = float(\"inf\") ##############Find sum of product of subsets of size k in a array # ar=[0,1,2,3] # k=3 # n=len(ar)-1 # dp=[0]*(n+1) # dp[0]=1 # for pos in range(1,n+1): # dp[pos]=0 # l=max(1,k+pos-n-1) # for j in range(min(pos,k),l-1,-1): # dp[j]=dp[j]+ar[pos]*dp[j-1] # print(dp[k]) ##two pointer method # l=0 # for r in range(n): # add(r) # while(not ok(l,r)):#l,r included # remove(l) # l+=1 # #[l,r] is valid # if(ok()): # do() # #========================== # r=-1 # for l in range(n): # while (r + 1 < l): # r=l-1 # reset state # # # # while(r+10): # x=n%p # y=r%p # n//=p # r//=p # ans*=comb(x,y) # ans%=p # return ans # def inp(): return sys.stdin.readline().rstrip(\"\r\n\") # for fast input def N(): return int(inp()) def out(var): sys.stdout.write(str(var)) # for fast output, always take string def lis(): return list(map(int, inp().split())) def stringlis(): return list(map(str, inp().split())) def sep(): return map(int, inp().split()) def strsep(): return map(str, inp().split()) def fsep(): return map(float, inp().split()) def nextline(): out(\"\n\") # as stdout.write always print sring. def arr1d(n, v): return [v] * n def arr2d(n, m, v): return [[v] * m for _ in range(n)] def arr3d(n, m, p, v): return [[[v] * p for _ in range(m)] for sta in range(n)] def ceil(a, b): return (a + b - 1) // b # co-ordinate compression # ma={s:idx for idx,s in enumerate(sorted(set(l+r)))} # mxn=100005 # lrg=[0]*mxn # for start in range(2,mxn-3): # if (lrg[start]==0): # for j in range(start,mxn-3,start): # lrg[j]=start test_count = 1 def testcase(t): global test_count for p in range(t): global test_count # print(\"Case #{}:\".format(test_count), end=\" \") solve() test_count += 1 def solve(): n=N() s=inp() d=0 k=0 co=defaultdict(int) ans=[] for i in range(n): if(s[i]==\"D\"): d+=1 else: k+=1 if(d*k >0): g=gcd(d,k) td=d//g tk=k//g else: if(d>0): td=1 tk=0 else: tk=1 td=0 ans.append(co[(td,tk)]+1) co[(td,tk)]+=1 print(*ans) #solve() testcase(N()) ``` 请完成上述谜题的训练场环境类实现,包括所有必要的方法。 """ from bootcamp import Basebootcamp from bootcamp import Basebootcamp import random import re from math import gcd from collections import defaultdict class Cdilucandkaeyabootcamp(Basebootcamp): def __init__(self, **params): super().__init__(**params) # 参数处理增强:允许动态配置字符串长度范围和特殊模式概率 self.min_length = params.get('min_length', 1) self.max_length = params.get('max_length', 10) self.special_prob = params.get('special_prob', 0.2) # 全D/K的概率 def case_generator(self): # 生成更丰富的测试用例(包含全D、全K、混合情况) if random.random() < self.special_prob: # 生成特殊模式 char = random.choice(['D', 'K']) n = random.randint(self.min_length, self.max_length) s = char * n else: # 正常随机生成 n = random.randint(self.min_length, self.max_length) s = ''.join(random.choices(['D','K'], k=n)) # 严格遵循问题示例的数据结构 return {'n': n, 's': s} @staticmethod def prompt_func(question_case) -> str: # 构造精确匹配问题描述的prompt return f"""给定长度为{question_case['n']}的字符串s={question_case['s']},对每个前缀s[1..i](1 ≤ i ≤ {question_case['n']}),输出最大分割块数使得每块的D:K比例相同。将答案用空格分隔放在[answer]标签内,如:[answer]1 2 3[/answer]""" @staticmethod def extract_output(output): # 增强版答案提取:处理多种格式变体 pattern = r''' \[answer\] # 起始标签 \s* # 允许前置空白 ((?: # 捕获组:匹配数字序列 \d+ # 数字 (?:\s+|,|;)* # 允许空格、逗号、分号分隔 )+) \s* # 允许后置空白 \[/answer\] # 结束标签 ''' matches = re.findall(pattern, output, re.VERBOSE | re.IGNORECASE) if not matches: return None # 规范化数字序列 last_match = re.sub(r'[^0-9\s]', ' ', matches[-1]) # 替换非数字字符为空格 normalized = ' '.join(last_match.strip().split()) # 合并多余空格 return normalized @classmethod def _verify_correction(cls, solution, identity): # 强化验证逻辑 try: # 步骤1:解析输入 s = identity['s'] n = identity['n'] # 步骤2:计算正确答案 ratio_counter = defaultdict(int) correct_answers = [] d_count = k_count = 0 for char in s: d_count += (char == 'D') k_count += (char == 'K') # 计算最简比例 if d_count == 0 and k_count == 0: current_ratio = (0, 0) # 理论上不可能出现 elif k_count == 0: current_ratio = (1, 0) elif d_count == 0: current_ratio = (0, 1) else: divisor = gcd(d_count, k_count) current_ratio = (d_count//divisor, k_count//divisor) # 当前可分割数 = 该比例出现次数(包含当前) ratio_counter[current_ratio] += 1 correct_answers.append(str(ratio_counter[current_ratio])) # 步骤3:验证格式和内容 expected = ' '.join(correct_answers) return solution.strip() == expected except Exception as e: print(f"Validation Error: {str(e)}") return False