题意: 一个武器共有n+1级, 给出第i级升到i+1级的花费, 成功概率, 失败掉回第几级, 给出q次询问, 每次问从第l级升到第r级的期望花费.
可以发现这个题的期望具有可加性: 设 d p [ i ] dp[i] dp[i]表示 i i i升到 i + 1 i+1 i+1的期望花费, 那么 i i i升到 i + 2 i+2 i+2的花费就是 d p [ i ] + d p [ i + 1 ] dp[i]+dp[i+1] dp[i]+dp[i+1], 那么对于任意 l l l和 r r r只要求出 d p dp dp数组的前缀和即可 O ( 1 ) O(1) O(1)回答询问.
那么问题就转化为求
d
p
[
i
]
dp[i]
dp[i], 即每级的期望花费.
如果第j次升级成功, 那么花费就是a[i]; 如果第j次没有成功, 就要再从x[i]级升回i级, 然后再判断第j+1次有没有成功…
列个式子的话是这样: 期望花费=a[i]+(1-p[i])*(期望x[i] to i)*(a[i]+(1-p[i])*(期望x[i] to i)*…)
很显然加粗部分是递归的. 只要设期望花费为W, 加粗部分也会是W, 移一下项就能得到递推式.
d
p
[
i
]
=
(
a
[
i
]
+
(
1
−
p
[
i
]
)
∗
(
s
u
m
[
i
−
1
]
−
s
u
m
[
x
[
i
]
−
1
]
)
)
p
[
i
]
dp[i]=(\frac{a[i]+(1-p[i])*(sum[i-1]-sum[x[i]-1]))}{p[i]}
dp[i]=(p[i]a[i]+(1−p[i])∗(sum[i−1]−sum[x[i]−1])), 其中,
s
u
m
[
j
]
sum[j]
sum[j]表示
d
p
[
j
]
dp[j]
dp[j]的前缀和, 即从
1
1
1级升到
j
+
1
j+1
j+1级的期望花费.
注意加法取模可以不用 % m o d \%mod %mod,因为两个小于 m o d mod mod的数相加对 m o d mod mod取余只需要减掉一个 m o d mod mod就可以了(这样比较快).
这个题我用分数写不知道为啥会出现负数和分母为0的情况…
int n, q, x[M];
ll a[M], p[M], sum[M], dp[M];
inline ll MOD1(ll xx) {
if (xx >= mod)return xx - mod;
return xx;
}
void init() {
int _ = read();
while (_--) {
n = read(), q = read();
for (int i = 1; i <= n; ++i) {
ll r = read(), s = read();
x[i] = read(), a[i] = read();
p[i] = r * niYuan(s, mod) % mod;
dp[i] = MOD1(a[i] + MOD1(1 + mod - p[i]) * (MOD1(sum[i - 1] + mod - sum[x[i] - 1])) % mod)
* niYuan(p[i], mod) % mod;
// 相当于
// dp[i] = (a[i] + (1 - p[i]) * (sum[i - 1] - sum[x[i] - 1])) / p[i];
sum[i] = MOD1(sum[i - 1] + dp[i]);
}
while (q--) {
int l = read(), r = read();
write(MOD1(sum[r - 1] + mod - sum[l - 1]));
enter;
}
}
}