第九届河北省大学生程序设计竞赛 E题思路分享(dp,期望)
题意概述
需要连续击败 \(n\) 个 \(boss\) 才能通关,计算通关的期望挑战次数。
具体规则如下:
-
初始血量为满血 \(h\),从头开始每成功打完 \(k\) 个 \(boss\) 会有一个休息点,会在休息点回满血。
-
对于每一个 \(bos\)s,都有概率被 \(boss\) 秒杀,被秒杀的概率会受到掉血量的影响,满血时概率为 \(p_i\),每掉 \(1\) 滴血,这个概率会乘上一个倍数 \(x\)。
-
如果被第 \(i\) 个 \(boss\) 秒杀,那么本次挑战失败;否则,有 \(q_i\) 的概率受伤,受伤会掉 \(1\) 滴血,若血量变为 \(0\) 则也挑战失败。
-
每次挑战失败,都需要从头开始,成功打败第 \(n\) 个 \(boss\) 并且血量不为 \(0\) 则挑战成功。
\(1 \leq n \leq 5 \times 10^4\), \(1 \leq h \leq 5 \times 10^4\), \(0 \leq k < n\), \(100 < x' \leq 200\) 。
特殊地,\(k = 0\) 时表示不存在休息点,保证通关概率不为 \(0\) 。
思路
记通关的概率为 \(P\),根据几何分布期望公式,通关的期望挑战次数为 \(1 / P\) 。
考虑 \(dp\),无法存所有血量状态,考虑优化第二维的血量状态。
注意到被秒杀的概率随掉血量增加指数增长,推测掉血量不能太多。
具体的,记当前掉血量为 \(j\),被秒杀概率需要小于 \(1\) ,即:
\[p_i \times x^j \lt 1
\]
解得:
\[j \lt \left\lceil \frac{-\ln p_i}{\ln x} \right\rceil
\]
记这个上界为 \(mx_i\) 。
最坏的情况,\(x=1.01,p_i=0.01\),这样 \(mx_i\) 大概是 \(463\),第二维最多只需要开 \(500\) 。
得到这个性质之后, \(dp\) 转移即可。
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MOD = 1e9+7;
const double eps = 1e-9;
ll qpow(ll a,ll b){
ll res = 1;
while (b){
if (b&1){
res = res*a%MOD;
}
a = a*a%MOD;
b >>= 1;
}
return res;
}
void solve(){
int n,h,k,x;
cin >> n >> h >> k >> x;
vector<int> p(n+1),q(n+1);
for (int i=1;i<=n;i++){
cin >> q[i];
}
for (int i=1;i<=n;i++){
cin >> p[i];
}
vector<int> mx(n+1);
for (int i=1;i<=n;i++){
mx[i] = (int)ceil(-log(p[i]/100.0)/log(x/100.0)-eps);
}
int N = min(500,h);
vector<vector<ll>> dp(n+1,vector<ll>(N,0));
dp[0][0] = 1;
ll temp = qpow(100,MOD-2);
for (int i=1;i<=n;i++){
for (int j=0;j<min(mx[i],N);j++){
ll cur = dp[i-1][j]*((1-p[i]*temp%MOD*qpow(x*temp%MOD,j)%MOD+MOD)%MOD)%MOD;
dp[i][j] = (dp[i][j]+(1-q[i]*temp%MOD+MOD)%MOD*cur%MOD)%MOD;
if (j+1<N){
dp[i][j+1] = (dp[i][j+1]+q[i]*temp%MOD*cur%MOD)%MOD;
}
}
if (k!=0 && i%k==0){
for (int j=1;j<N;j++){
dp[i][0] = (dp[i][0]+dp[i][j])%MOD;
dp[i][j] = 0;
}
}
}
ll res = 0;
for (int j=0;j<N;j++){
res = (res+dp[n][j])%MOD;
}
cout << qpow(res,MOD-2) << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号