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

184 lines
6.3 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.

"""#
### 谜题描述
In the probability theory the following paradox called Benford's law is known: \"In many lists of random numbers taken from real sources, numbers starting with digit 1 occur much more often than numbers starting with any other digit\" (that's the simplest form of the law).
Having read about it on Codeforces, the Hedgehog got intrigued by the statement and wishes to thoroughly explore it. He finds the following similar problem interesting in particular: there are N random variables, the i-th of which can take any integer value from some segment [Li;Ri] (all numbers from this segment are equiprobable). It means that the value of the i-th quantity can be equal to any integer number from a given interval [Li;Ri] with probability 1 / (Ri - Li + 1).
The Hedgehog wants to know the probability of the event that the first digits of at least K% of those values will be equal to one. In other words, let us consider some set of fixed values of these random variables and leave only the first digit (the MSD — most significant digit) of each value. Then let's count how many times the digit 1 is encountered and if it is encountered in at least K per cent of those N values, than such set of values will be called a good one. You have to find the probability that a set of values of the given random variables will be a good one.
Input
The first line contains number N which is the number of random variables (1 ≤ N ≤ 1000). Then follow N lines containing pairs of numbers Li, Ri, each of whom is a description of a random variable. It is guaranteed that 1 ≤ Li ≤ Ri ≤ 1018.
The last line contains an integer K (0 ≤ K ≤ 100).
All the numbers in the input file are integers.
Please, do not use %lld specificator to read or write 64-bit integers in C++. It is preffered to use cin (also you may use %I64d).
Output
Print the required probability. Print the fractional number with such a precision that the relative or absolute error of the result won't exceed 10 - 9.
Examples
Input
1
1 2
50
Output
0.500000000000000
Input
2
1 2
9 11
50
Output
0.833333333333333
Here is a reference code to solve this task. You can use this to help you genereate cases or validate the solution.
```python
N = input()
T = [1]+[0]*N
for i in range(N):
L,R = map(int,raw_input().split())
c = 1
n = 0
while c<=10**18:
n += max(0,min(R,2*c-1)-max(L,c)+1)
c *= 10
p = float(n)/(R-L+1)
B = T
T = [B[0]*(1-p)]+[0]*N
for j in range(1,N+1):
T[j] = B[j]*(1-p)+B[j-1]*p
K = input()
print sum(T[(N*K+99)/100:])
```
请完成上述谜题的训练场环境类实现,包括所有必要的方法。
"""
from bootcamp import Basebootcamp
from bootcamp import Basebootcamp
import math
import re
import random
class Cfirstdigitlawbootcamp(Basebootcamp):
def __init__(self, max_N=10, **params):
super().__init__(**params)
self.max_N = max_N # 控制问题规模以便测试
def case_generator(self):
N = random.randint(1, self.max_N)
variables = []
for _ in range(N):
# 生成更丰富的数值区间分布
if random.random() < 0.3:
# 特殊形式生成以1开头的大范围数值
exp = random.randint(0, 17)
Li = 10**exp
Ri = 10**exp * 2 - 1
else:
# 通用生成逻辑
exp = random.randint(0, 18)
Li = random.randint(10**exp // 10, 10**exp - 1) if exp > 0 else 1
max_exp_ri = random.randint(exp, 18)
max_ri = min(10**max_exp_ri - 1, 10**18)
Ri = random.randint(Li, max_ri)
variables.append({"L": Li, "R": Ri})
K = random.randint(0, 100)
return {
"N": N,
"variables": variables,
"K": K
}
@staticmethod
def prompt_func(question_case):
N = question_case['N']
variables = question_case['variables']
K = question_case['K']
required_num = (N * K + 99) // 100
problem = f"""根据本福特定律研究问题,请计算{N}个独立随机变量满足条件的概率:
每个变量的取值范围如下:"""
for idx, var in enumerate(variables, 1):
problem += f"\n变量{idx}: [{var['L']}, {var['R']}],其中每个整数等概率出现"
problem += f"""
要求计算至少{required_num}个变量的最高位为1的概率即至少达到{K}%的比例)。
请输出精确到小数点后15位的概率值并确保绝对/相对误差≤1e-9。答案请用[answer]和[/answer]标签包裹。
示例:
[answer]0.123456789012345[/answer]"""
return problem
@staticmethod
def extract_output(output):
matches = re.findall(r'\[answer\]([\d.eE+-]+)\s*\[/answer\]', output)
if not matches:
return None
try:
return float(matches[-1].strip().replace(',', ''))
except ValueError:
return None
@classmethod
def _verify_correction(cls, solution, identity):
try:
N = identity['N']
variables = identity['variables']
K = identity['K']
# 动态规划数组初始化
dp = [1.0] + [0.0] * N
for var in variables:
L, R = var['L'], var['R']
total = R - L + 1
# 计算有效数目
valid_count = 0
c = 1
while c <= 1e18:
lower_bound = max(L, c)
upper_bound = min(R, 2 * c - 1)
valid_count += max(0, upper_bound - lower_bound + 1)
c *= 10
# 更新概率分布
p = valid_count / total
new_dp = [0.0] * (N + 1)
new_dp[0] = dp[0] * (1 - p)
for j in range(1, N + 1):
new_dp[j] = dp[j] * (1 - p) + dp[j-1] * p
dp = new_dp
# 计算阈值
required = (N * K + 99) // 100
threshold = max(0, min(required, N))
correct_prob = sum(dp[threshold:]) if threshold <= N else 0.0
# 浮点数精确校验
return math.isclose(solution, correct_prob, rel_tol=1e-9, abs_tol=1e-12)
except:
return False