题意: 一个武器共有n+1级, 给出第i级升到i+1级的花费, 成功概率, 失败掉回第几级, 给出q次询问, 每次问从第l级升到第r级的期望花费.
可以发现这个题的期望具有可加性: 设dp[i]dp[i]dp[i]表示iii升到i+1i+1i+1的期望花费, 那么iii升到i+2i+2i+2的花费就是dp[i]+dp[i+1]dp[i]+dp[i+1]dp[i]+dp[i+1], 那么对于任意lll和rrr只要求出dpdpdp数组的前缀和即可O(1)O(1)O(1)回答询问.
那么问题就转化为求dp[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, 移一下项就能得到递推式.
dp[i]=(a[i]+(1−p[i])∗(sum[i−1]−sum[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])), 其中, sum[j]sum[j]sum[j]表示dp[j]dp[j]dp[j]的前缀和, 即从111级升到j+1j+1j+1级的期望花费.
注意加法取模可以不用%mod\%mod%mod,因为两个小于modmodmod的数相加对modmodmod取余只需要减掉一个modmodmod就可以了(这样比较快).
这个题我用分数写不知道为啥会出现负数和分母为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;
}
}
}