mirror of
https://github.com/InternLM/InternBootcamp.git
synced 2026-04-23 16:55:02 +00:00
init-commit
This commit is contained in:
commit
18a552597a
3461 changed files with 1150579 additions and 0 deletions
301
internbootcamp/bootcamp/cneedforpinkslips/cneedforpinkslips.py
Executable file
301
internbootcamp/bootcamp/cneedforpinkslips/cneedforpinkslips.py
Executable file
|
|
@ -0,0 +1,301 @@
|
|||
"""#
|
||||
|
||||
### 谜题描述
|
||||
After defeating a Blacklist Rival, you get a chance to draw 1 reward slip out of x hidden valid slips. Initially, x=3 and these hidden valid slips are Cash Slip, Impound Strike Release Marker and Pink Slip of Rival's Car. Initially, the probability of drawing these in a random guess are c, m, and p, respectively. There is also a volatility factor v. You can play any number of Rival Races as long as you don't draw a Pink Slip. Assume that you win each race and get a chance to draw a reward slip. In each draw, you draw one of the x valid items with their respective probabilities. Suppose you draw a particular item and its probability of drawing before the draw was a. Then,
|
||||
|
||||
* If the item was a Pink Slip, the quest is over, and you will not play any more races.
|
||||
* Otherwise,
|
||||
1. If a≤ v, the probability of the item drawn becomes 0 and the item is no longer a valid item for all the further draws, reducing x by 1. Moreover, the reduced probability a is distributed equally among the other remaining valid items.
|
||||
2. If a > v, the probability of the item drawn reduces by v and the reduced probability is distributed equally among the other valid items.
|
||||
|
||||
|
||||
|
||||
For example,
|
||||
|
||||
* If (c,m,p)=(0.2,0.1,0.7) and v=0.1, after drawing Cash, the new probabilities will be (0.1,0.15,0.75).
|
||||
* If (c,m,p)=(0.1,0.2,0.7) and v=0.2, after drawing Cash, the new probabilities will be (Invalid,0.25,0.75).
|
||||
* If (c,m,p)=(0.2,Invalid,0.8) and v=0.1, after drawing Cash, the new probabilities will be (0.1,Invalid,0.9).
|
||||
* If (c,m,p)=(0.1,Invalid,0.9) and v=0.2, after drawing Cash, the new probabilities will be (Invalid,Invalid,1.0).
|
||||
|
||||
|
||||
|
||||
You need the cars of Rivals. So, you need to find the expected number of races that you must play in order to draw a pink slip.
|
||||
|
||||
Input
|
||||
|
||||
The first line of input contains a single integer t (1≤ t≤ 10) — the number of test cases.
|
||||
|
||||
The first and the only line of each test case contains four real numbers c, m, p and v (0 < c,m,p < 1, c+m+p=1, 0.1≤ v≤ 0.9).
|
||||
|
||||
Additionally, it is guaranteed that each of c, m, p and v have at most 4 decimal places.
|
||||
|
||||
Output
|
||||
|
||||
For each test case, output a single line containing a single real number — the expected number of races that you must play in order to draw a Pink Slip.
|
||||
|
||||
Your answer is considered correct if its absolute or relative error does not exceed 10^{-6}.
|
||||
|
||||
Formally, let your answer be a, and the jury's answer be b. Your answer is accepted if and only if \frac{|a - b|}{max{(1, |b|)}} ≤ 10^{-6}.
|
||||
|
||||
Example
|
||||
|
||||
Input
|
||||
|
||||
|
||||
4
|
||||
0.2 0.2 0.6 0.2
|
||||
0.4 0.2 0.4 0.8
|
||||
0.4998 0.4998 0.0004 0.1666
|
||||
0.3125 0.6561 0.0314 0.2048
|
||||
|
||||
|
||||
Output
|
||||
|
||||
|
||||
1.532000000000
|
||||
1.860000000000
|
||||
5.005050776521
|
||||
4.260163673896
|
||||
|
||||
Note
|
||||
|
||||
For the first test case, the possible drawing sequences are:
|
||||
|
||||
* P with a probability of 0.6;
|
||||
* CP with a probability of 0.2⋅ 0.7 = 0.14;
|
||||
* CMP with a probability of 0.2⋅ 0.3⋅ 0.9 = 0.054;
|
||||
* CMMP with a probability of 0.2⋅ 0.3⋅ 0.1⋅ 1 = 0.006;
|
||||
* MP with a probability of 0.2⋅ 0.7 = 0.14;
|
||||
* MCP with a probability of 0.2⋅ 0.3⋅ 0.9 = 0.054;
|
||||
* MCCP with a probability of 0.2⋅ 0.3⋅ 0.1⋅ 1 = 0.006.
|
||||
|
||||
So, the expected number of races is equal to 1⋅ 0.6 + 2⋅ 0.14 + 3⋅ 0.054 + 4⋅ 0.006 + 2⋅ 0.14 + 3⋅ 0.054 + 4⋅ 0.006 = 1.532.
|
||||
|
||||
For the second test case, the possible drawing sequences are:
|
||||
|
||||
* P with a probability of 0.4;
|
||||
* CP with a probability of 0.4⋅ 0.6 = 0.24;
|
||||
* CMP with a probability of 0.4⋅ 0.4⋅ 1 = 0.16;
|
||||
* MP with a probability of 0.2⋅ 0.5 = 0.1;
|
||||
* MCP with a probability of 0.2⋅ 0.5⋅ 1 = 0.1.
|
||||
|
||||
|
||||
|
||||
So, the expected number of races is equal to 1⋅ 0.4 + 2⋅ 0.24 + 3⋅ 0.16 + 2⋅ 0.1 + 3⋅ 0.1 = 1.86.
|
||||
|
||||
Here is a reference code to solve this task. You can use this to help you genereate cases or validate the solution.
|
||||
```python
|
||||
PREC = 0.00000005
|
||||
|
||||
def floatEq(a, b):
|
||||
return abs(a-b) < PREC
|
||||
|
||||
def f(c, m, p, v, n):
|
||||
r = (n+1)*p
|
||||
if c is not None and (c < v or floatEq(c, v)):
|
||||
if m is not None:
|
||||
r += c*f(None, m+c/2.0, p+c/2.0, v, n+1)
|
||||
else:
|
||||
r += c*f(None, None, p+c, v, n+1)
|
||||
elif c is not None and c > v:
|
||||
if m is not None:
|
||||
r += c*f(c-v, m+v/2.0, p+v/2.0, v, n+1)
|
||||
else:
|
||||
r += c*f(c-v, None, p+v, v, n+1)
|
||||
if m is not None and (m < v or floatEq(m, v)):
|
||||
if c is not None:
|
||||
r += m*f(c+m/2.0, None, p+m/2.0, v, n+1)
|
||||
else:
|
||||
r += m*f(None, None, p+m, v, n+1)
|
||||
elif m is not None and m > v:
|
||||
if c is not None:
|
||||
r += m*f(c+v/2.0, m-v, p+v/2.0, v, n+1)
|
||||
else:
|
||||
r += m*f(None, m-v, p+v, v, n+1)
|
||||
return r
|
||||
I=lambda: map(float, raw_input().split())
|
||||
t = input()
|
||||
for _ in xrange(t):
|
||||
c, m, p, v = I()
|
||||
print f(c, m, p, v, 0)
|
||||
```
|
||||
|
||||
|
||||
请完成上述谜题的训练场环境类实现,包括所有必要的方法。
|
||||
"""
|
||||
|
||||
from bootcamp import Basebootcamp
|
||||
import random
|
||||
import re
|
||||
from bootcamp import Basebootcamp
|
||||
|
||||
class Cneedforpinkslipsbootcamp(Basebootcamp):
|
||||
def __init__(self, **params):
|
||||
self.params = params
|
||||
super().__init__(**params)
|
||||
|
||||
def case_generator(self):
|
||||
# 随机选择生成类型:普通案例、含极值p、初始值触发无效条件
|
||||
case_type = random.choice(['normal', 'extreme_p', 'low_prob'])
|
||||
|
||||
if case_type == 'normal':
|
||||
# 标准生成方式
|
||||
a = random.randint(1, 9998)
|
||||
max_b = 10000 - a - 1 # 保证至少留1给d
|
||||
b = random.randint(1, max_b)
|
||||
d = 10000 - a - b
|
||||
c = round(a / 10000, 4)
|
||||
m = round(b / 10000, 4)
|
||||
p = round(d / 10000, 4)
|
||||
v = round(random.randint(1000, 9000) / 10000, 4)
|
||||
|
||||
elif case_type == 'extreme_p':
|
||||
# 生成极小的p值(类似第三个测试案例)
|
||||
p = round(random.choice([0.0001, 0.0002, 0.0003, 0.0004]), 4)
|
||||
remaining = round(1 - p, 4)
|
||||
c = round(remaining * random.uniform(0.4, 0.6), 4)
|
||||
m = round(remaining - c, 4)
|
||||
v = round(random.uniform(0.15, 0.25), 4)
|
||||
|
||||
elif case_type == 'low_prob':
|
||||
# 生成会立即触发无效条件的案例
|
||||
v_val = round(random.uniform(0.1, 0.3), 4)
|
||||
target = random.choice(['c', 'm'])
|
||||
if target == 'c':
|
||||
c = round(random.uniform(0.01, v_val), 4)
|
||||
remaining = 1 - c
|
||||
m = round(remaining * random.uniform(0.3, 0.7), 4)
|
||||
p = round(remaining - m, 4)
|
||||
else:
|
||||
m = round(random.uniform(0.01, v_val), 4)
|
||||
remaining = 1 - m
|
||||
c = round(remaining * random.uniform(0.3, 0.7), 4)
|
||||
p = round(remaining - c, 4)
|
||||
v = v_val
|
||||
|
||||
# 校验并修正浮点精度
|
||||
total = round(c + m + p, 4)
|
||||
if total != 1.0:
|
||||
p = round(1 - c - m, 4)
|
||||
|
||||
return {
|
||||
'c': c,
|
||||
'm': m,
|
||||
'p': p,
|
||||
'v': v
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def prompt_func(question_case):
|
||||
c = question_case['c']
|
||||
m = question_case['m']
|
||||
p = question_case['p']
|
||||
v = question_case['v']
|
||||
prompt = f"""你刚刚击败了一个黑名单对手,获得了一个抽取奖励纸条的机会。初始时有三个有效纸条:现金纸条(Cash Slip,初始概率为{c:.4f})、扣押解除标记(Impound Strike Release Marker,初始概率为{m:.4f})和对手车辆的粉色纸条(Pink Slip,初始概率为{p:.4f})。每次比赛获胜后,你可以抽取一张纸条。只要未抽到粉色纸条,你就可以继续参赛。每次抽取后,根据以下规则调整剩余纸条的概率:
|
||||
|
||||
1. 如果抽到的是粉色纸条,游戏结束,不再进行任何比赛。
|
||||
2. 如果抽到的是其他纸条(如现金或解除标记):
|
||||
- 若该纸条当前的抽取概率a小于等于波动因子v(当前v={v:.4f}),则该纸条变为无效(概率变为0),其原有概率平均分配给剩余的合法纸条。
|
||||
- 若该纸条的概率a大于v,则其概率减少v,减少的部分平均分配给其他合法纸条。
|
||||
|
||||
你的任务是计算需要进行的比赛的期望次数(即抽到粉色纸条之前的总抽取次数)。
|
||||
|
||||
输入数据为四个实数:{c:.4f} {m:.4f} {p:.4f} {v:.4f}。请严格根据上述规则计算期望值,并确保答案的绝对或相对误差不超过1e-6。答案必须包含足够多的小数位(例如,类似1.532000000000的格式)。
|
||||
|
||||
请将计算出的期望值放在[answer]和[/answer]的标签内。例如:[answer]1.532000000000[/answer]。"""
|
||||
return prompt
|
||||
|
||||
@staticmethod
|
||||
def extract_output(output):
|
||||
matches = re.findall(r'\[answer\]\s*([\d.]+)\s*\[/answer\]', output, re.IGNORECASE)
|
||||
if not matches:
|
||||
return None
|
||||
try:
|
||||
return float(matches[-1].strip())
|
||||
except:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def _verify_correction(cls, solution, identity):
|
||||
expected = cls._calculate_expected(identity['c'], identity['m'], identity['p'], identity['v'])
|
||||
if solution is None:
|
||||
return False
|
||||
try:
|
||||
solution_float = float(solution)
|
||||
except:
|
||||
return False
|
||||
# 双重验证机制
|
||||
abs_error = abs(solution_float - expected)
|
||||
if abs_error < 1e-6:
|
||||
return True
|
||||
rel_error = abs_error / max(1.0, abs(expected))
|
||||
return rel_error <= 1e-6
|
||||
|
||||
@staticmethod
|
||||
def _calculate_expected(c_val, m_val, p_val, v_val):
|
||||
PREC = 1e-8
|
||||
|
||||
def float_eq(a, b):
|
||||
return abs(a - b) < PREC
|
||||
|
||||
memo = {}
|
||||
|
||||
def f(c, m, p, n):
|
||||
key = (c if c is None else round(c,8),
|
||||
m if m is None else round(m,8),
|
||||
n)
|
||||
if key in memo:
|
||||
return memo[key]
|
||||
|
||||
total = (n+1)*p
|
||||
remaining = []
|
||||
if c is not None:
|
||||
remaining.append(('c', c))
|
||||
if m is not None:
|
||||
remaining.append(('m', m))
|
||||
|
||||
for item, value in remaining:
|
||||
if item == 'c':
|
||||
current_c = value
|
||||
if current_c < v_val or float_eq(current_c, v_val):
|
||||
# Case 1: becomes invalid
|
||||
if m is not None:
|
||||
delta = current_c / 2
|
||||
contribution = current_c * f(None, m+delta, p+delta, n+1)
|
||||
else:
|
||||
contribution = current_c * f(None, None, p+current_c, n+1)
|
||||
else:
|
||||
# Case 2: reduce by v
|
||||
new_c = current_c - v_val
|
||||
if m is not None:
|
||||
delta = v_val / 2
|
||||
contribution = current_c * f(new_c, m+delta, p+delta, n+1)
|
||||
else:
|
||||
contribution = current_c * f(new_c, None, p+v_val, n+1)
|
||||
total += contribution
|
||||
elif item == 'm':
|
||||
current_m = value
|
||||
if current_m < v_val or float_eq(current_m, v_val):
|
||||
# Case 1: becomes invalid
|
||||
if c is not None:
|
||||
delta = current_m / 2
|
||||
contribution = current_m * f(c+delta, None, p+delta, n+1)
|
||||
else:
|
||||
contribution = current_m * f(None, None, p+current_m, n+1)
|
||||
else:
|
||||
# Case 2: reduce by v
|
||||
new_m = current_m - v_val
|
||||
if c is not None:
|
||||
delta = v_val / 2
|
||||
contribution = current_m * f(c+delta, new_m, p+delta, n+1)
|
||||
else:
|
||||
contribution = current_m * f(None, new_m, p+v_val, n+1)
|
||||
total += contribution
|
||||
memo[key] = total
|
||||
return total
|
||||
|
||||
c = c_val if c_val > 1e-8 else None
|
||||
m = m_val if m_val > 1e-8 else None
|
||||
p = p_val
|
||||
|
||||
return f(c, m, p, 0)
|
||||
Loading…
Add table
Add a link
Reference in a new issue