mirror of
https://github.com/InternLM/InternBootcamp.git
synced 2026-04-19 12:58:04 +00:00
294 lines
9.8 KiB
Python
Executable file
294 lines
9.8 KiB
Python
Executable file
"""#
|
||
|
||
### 谜题描述
|
||
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 yi(1-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
|