InternBootcamp/internbootcamp/bootcamp/crunningtrack/crunningtrack.py
2025-05-23 15:27:15 +08:00

294 lines
9.8 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""#
### 谜题描述
A boy named Ayrat lives on planet AMI-1511. Each inhabitant of this planet has a talent. Specifically, Ayrat loves running, moreover, just running is not enough for him. He is dreaming of making running a real art.
First, he wants to construct the running track with coating t. On planet AMI-1511 the coating of the track is the sequence of colored blocks, where each block is denoted as the small English letter. Therefore, every coating can be treated as a string.
Unfortunately, blocks aren't freely sold to non-business customers, but Ayrat found an infinite number of coatings s. Also, he has scissors and glue. Ayrat is going to buy some coatings s, then cut out from each of them exactly one continuous piece (substring) and glue it to the end of his track coating. Moreover, he may choose to flip this block before glueing it. Ayrat want's to know the minimum number of coating s he needs to buy in order to get the coating t for his running track. Of course, he also want's to know some way to achieve the answer.
Input
First line of the input contains the string s — the coating that is present in the shop. Second line contains the string t — the coating Ayrat wants to obtain. Both strings are non-empty, consist of only small English letters and their length doesn't exceed 2100.
Output
The first line should contain the minimum needed number of coatings n or -1 if it's impossible to create the desired coating.
If the answer is not -1, then the following n lines should contain two integers xi and yi — numbers of ending blocks in the corresponding piece. If xi ≤ yi then this piece is used in the regular order, and if xi > yi piece is used in the reversed order. Print the pieces in the order they should be glued to get the string t.
Examples
Input
abc
cbaabc
Output
2
3 1
1 3
Input
aaabrytaaa
ayrat
Output
3
1 1
6 5
8 7
Input
ami
no
Output
-1
Note
In the first sample string \"cbaabc\" = \"cba\" + \"abc\".
In the second sample: \"ayrat\" = \"a\" + \"yr\" + \"at\".
Here is a reference code to solve this task. You can use this to help you genereate cases or validate the solution.
```python
s = raw_input()
t = raw_input()
rev = s[::-1]
t=t+\"#\"
ans=[]
temp=t[0]
n=len(s)
for i in xrange(1,len(t)):
cur = temp+t[i]
if cur in s or cur in rev:
temp=cur
else:
if temp in s:
start = s.find(temp)
ans.append((start+1,start+len(temp)))
elif temp in rev:
start = rev.find(temp)
ans.append((n-start,n-start-len(temp)+1))
else :
print -1
exit(0)
temp=t[i]
print len(ans)
for i in xrange(len(ans)):
print ans[i][0],ans[i][1]
```
请完成上述谜题的训练场环境类实现,包括所有必要的方法。
"""
from bootcamp import Basebootcamp
import re
import random
from string import ascii_lowercase
from bootcamp import Basebootcamp
class Crunningtrackbootcamp(Basebootcamp):
def __init__(self, s_min_length=3, s_max_length=10, allow_unsolvable=False, unsolvable_prob=0.2):
self.s_min_length = s_min_length
self.s_max_length = s_max_length
self.allow_unsolvable = allow_unsolvable
self.unsolvable_prob = unsolvable_prob
def case_generator(self):
# 生成满足条件的s
while True:
s = ''.join(random.choices(ascii_lowercase,
k=random.randint(self.s_min_length, self.s_max_length)))
if len(set(s)) >= 2: # 确保s至少有2个不同字符
break
# 生成可解的t案例
if not self.allow_unsolvable or random.random() > self.unsolvable_prob:
for _ in range(100): # 最多尝试100次生成合法案例
# 基于s生成保证可解的t
t_parts = []
num_parts = random.randint(1, 5)
for _ in range(num_parts):
# 确保每次切割都有效
max_len = len(s) - 1 if len(s) > 1 else 1
part_len = random.randint(1, max_len)
start = random.randint(0, len(s)-part_len)
reverse = random.random() < 0.5
t_parts.append(s[start:start+part_len][::-1] if reverse else s[start:start+part_len])
t = ''.join(t_parts)
ans_ref = self._solve_reference(s, t)
if ans_ref != -1 and len(ans_ref) == num_parts:
return {'s': s, 't': t, 'ans_ref': ans_ref}
# 生成保证可解的默认案例
default_s = 'abc'
default_t = default_s[::-1] + default_s # 'cbaabc'
ans_ref = self._solve_reference(default_s, default_t)
return {'s': default_s, 't': default_t, 'ans_ref': ans_ref}
# 生成不可解案例
else:
# 策略1插入非法字符
if random.random() < 0.5:
invalid_char = random.choice([c for c in ascii_lowercase if c not in s])
return {'s': s, 't': invalid_char*(len(s)+1), 'ans_ref': -1}
# 策略2构造无法分割的合法t
for _ in range(100):
# 生成交替模式如abababc (s长度超过3时)
t = (s[:2] * 3)[:random.randint(5, 15)]
if self._solve_reference(s, t) == -1:
return {'s': s, 't': t, 'ans_ref': -1}
# 策略3强制构造不可解案例
critical_char = s[0]
t = critical_char * (len(s)*2) # 超过s中连续出现的最大长度
return {'s': s, 't': t, 'ans_ref': -1}
@staticmethod
def _solve_reference(s, t):
rev_s = s[::-1]
result = []
current = t[0]
for c in t[1:]:
test_str = current + c
if test_str in s or test_str in rev_s:
current = test_str
else:
# 寻找最长匹配
found = False
for l in range(len(current), 0, -1):
substr = current[:l]
if substr in s:
start = s.index(substr)
result.append((start+1, start+l))
current = current[l:] + c
found = True
break
elif substr in rev_s:
start = rev_s.index(substr)
result.append((len(s)-start, len(s)-start-l+1))
current = current[l:] + c
found = True
break
if not found:
return -1
# 处理最后剩余部分
if current:
if current in s:
start = s.index(current)
result.append((start+1, start+len(current)))
elif current in rev_s:
start = rev_s.index(current)
result.append((len(s)-start, len(s)-start-len(current)+1))
else:
return -1
return result if result else -1
@staticmethod
def prompt_func(question_case) -> str:
s = question_case['s']
t = question_case['t']
return f"""你需要帮助Ayrat用最少段商店涂层s可反转拼接出目标涂层t。
输入:
s = {s}
t = {t}
输出要求:
首行为最小段数n无法完成输出-1
随后每行给出xi yi1-based索引xi≤yi正向使用xi>yi反向使用
将最终答案置于[answer]和[/answer]之间。示例:
[answer]
2
3 1
1 3
[/answer]"""
@staticmethod
def extract_output(output):
# 增强匹配模式,允许各种空白字符
matches = re.findall(r'\[answer\][\s]*(.*?)[\s]*\[/answer\]', output, re.DOTALL)
if not matches:
return None
content = matches[-1].strip()
lines = [line.strip() for line in content.split('\n') if line.strip()]
if not lines:
return None
try:
# 处理首行可能的多余字符(如-1后面带说明
first_line = lines[0].split()[0]
if first_line == '-1':
return -1
n = int(first_line)
if len(lines) < n+1 or n <= 0:
return None
parts = []
for line in lines[1:n+1]:
# 允许各种分隔符(空格、逗号等)
nums = re.findall(r'-?\d+', line)
if len(nums) != 2:
return None
x, y = map(int, nums)
parts.append((x, y))
return parts
except Exception as e:
return None
@classmethod
def _verify_correction(cls, solution, identity):
# 验证不可解情况
if identity['ans_ref'] == -1:
return solution == -1
# 验证可解情况
if solution == -1:
return False
# 类型检查
if not isinstance(solution, list) or len(solution) != len(identity['ans_ref']):
return False
s = identity['s']
t = identity['t']
reconstructed = []
for x, y in solution:
# 坐标有效性检查
if not (1 <= x <= len(s)) or not (1 <= y <= len(s)):
return False
if x <= y:
# 正向子串检查
if s[x-1:y] not in s:
return False
reconstructed.append(s[x-1:y])
else:
# 反向子串检查
rev_sub = s[y-1:x][::-1]
if rev_sub not in s:
return False
reconstructed.append(rev_sub)
return ''.join(reconstructed) == t