9月份打的了,当时考场上很紧张。一开始的思路确实是想用C++逐步模拟,但是实在是太麻烦了(
后来突然想到能不能直接定义求导呢?之前看过吴恩达的机器学习课程,里面在讲梯度的时候(下图),特意讲了梯度检验法(用数值求解验证解析求解的正确性,经典对拍思路)
下面是更详细的公式说明:
于是尝试了一下默认精度,发现只能通过部分样例。。(精度肯定不够,毕竟mod都是1e9+7了)
突然想到python有一个decimal高精库,于是赶紧使用py构造出字符串表达式(然后可以用exec动态赋值执行,非常方便,py大法好!!!)。由于是一道纯模拟题,输入规模非常小可以完全不需要考考虑时间复杂度。
下面是考场上写的代码:(用时171ms,9.484MB,100%通过)
(可以在这个链接里提交你的代码:计算机软件能力认证考试系统)
from decimal import *
getcontext().prec = 1000 # 设置精度为1000位小数
# 输入n和m
n, m = list(map(eval, input().split()))
# 输入表达式字符串
f_str = input()
items = f_str.split() # 将表达式字符串按空格拆分为列表
st = [] # 初始化一个空栈
opts = {'+', '-', '*', '/'} # 运算符集合
i = 0
while i < len(items):
e = items[i]
i += 1
if e not in opts: # 如果当前元素不是运算符
st.append(e) # 将其压入栈中
else:
e1 = st.pop() # 弹出栈顶元素作为第一个操作数
e2 = st.pop() # 再弹出栈顶元素作为第二个操作数
# 判断操作数是否为数字或以正负号开头的字符串,如果是则构造 Decimal 类型的字符串
if e1[0].isdigit() or e1[0] in ['+', '-']:
e1 = f"Decimal('{e1}')"
if e2[0].isdigit() or e2[0] in ['+', '-']:
e2 = f"Decimal('{e2}')"
r = f'({e2}{e}{e1})' # 构造运算表达式
st.append(r) # 将结果压入栈中
f = st[0] # 获取最终的运算表达式
# 1e-901 当做我们的delta
delta = Decimal('0.' + '0' * 900 + '1') # 定义一个极小的增量
mod = Decimal('1000000007') # 模值
for x in range(m):
line = input().split() # 获取输入的一行数据并按空格分割
i = eval(line[0]) # 第一个元素是索引值,将其转换为整数
for y in range(1, len(line)):
value = eval(line[y]) # 将每个元素转换为相应的数值
exec(f'x{y}=Decimal({line[y]})') # 为每个变量赋值为对应的 Decimal 类型的值
y1 = eval(f) # 计算运算表达式的值
value = Decimal(line[i]) - delta # 获取索引对应的值并减去一个极小的增量
exec(f'x{i}=Decimal(line[i]) - delta') # 对索引对应的值赋值为减去增量后的值
y2 = eval(f) # 重新计算运算表达式的值
ans = (y1 - y2) / delta # 计算差值并除以增量
# 下面循环最多执行2次,复杂度是O(1)
while not Decimal('0') <= ans < mod: # 对结果进行取模操作,使其在 [0, mod) 范围内
if ans < Decimal('0'):
ans = ans % mod + mod # 手动调整到 [0, mod) 区间
else:
ans = ans % mod
print(round(ans, 0)) # 输出结果取整后的值