题目链接:https://codeforces.com/gym/104396/problem/F
题意:初始有a朵小花,一次操作可以消耗b朵小花合成1朵大花,同时一次操作可以从两个技能中选择一个,一个是有p%的概率消耗b朵小花合成2朵大花,一个是有q%的概率消耗b朵小花合成1朵大花+1朵小花,问最大期望合成的大花数量是多少
之前没怎么写过期望dp 碰到就寄了 赛时dp转移写的i从大到小 还分类讨论了好几次 苦苦不能过样例2 uu
dp[i]代表有i朵小花时 大花个数的最大期望值
i从1到a进行dp dp[a]为答案
上面代表选择p的技能 下面代表选择q的技能 转移由题目内容可以推出
需要注意的是i-b和i-b+1数组下标不能为负数
有一个很重要的原因就是 样例为4 2的时候 dp[1]=0 因为只有1朵小花是无法合成的 而我从大到小dp没有考虑这个初始转移情况所以错了
坑点 注意特判:b=1的时候 需要从两个技能中选择其中一个一直进行操作 输出更大的那个答案
选择p的时候 dp[i] = p * (dp[i-b] + 2) + (1-p) * (dp[i-b] + 1);同样遍历到dp[a]为答案
选择q的时候 需要推一个级数求和 或者可以跑循环直到影响小于1e-9为止
我们假设a为1的时候进行q技能操作 那么得到大花数量X可以为1 2 3... n
P(X=1) =(1-q) 说明第一次技能没有实现
P(X=2) =q * (1-q) 说明第一次技能实现 第二次没有实现 一共得到2朵大花
以此类推 P(X=n) =q^(n-1) * (1-q) 前n-1次技能实现 第n次没有实现 一共得到n朵大花
根据期望的定义 可以知道EX=1*P(X=1) + 2*P(X=2) + ... + n*P(X=n) + ...
即EX=(1-q) + 2*q*(1-q) + 3*q^2*(1-q) + ... + n*q^(n-1)*(1-q) + ...
提出公因式(1-q)有 EX/(1-q) = 1 + 2q + 3q^2 + ... + nq^(n-1) + ...
如果你直接知道右式的值 就可以直接用来计算了 如果不知道的话还是要推一下
我们想办法计算右式的值 可以发现右式是由 S = 1 + q + q^2 + q^3 + ... + q^n + ... 求导得来
S的值可以用等比数列求和 由于n趋向无穷大 0<q<1 所以q^n近似为0 得到S=1/(1-q)
S的值也可以用q*S-S = 1 提出S 得到S=1/(1-q)
两边同时求导可以得到 S' = 1 + 2q + 3q^2 + ... + nq^(n-1) + ... = 1 / (1-q)^2 = EX/(1-q)
再把(1-q)乘回去就可以得到 EX = 1/(1-q)
这是进行一次q操作的期望值 初始有a朵小花就可以进行a次这样的类似操作 所以答案是a/(1-q)
这个值和p操作的dp[a]值取最大输出即可
(等之后学了latex再看看把式子写的好看一点x 先放上来再说
核心代码:
ll a, b;
ld p, q;
ld dp[N];
void solve()
{
cin >> a >> b >> p >> q;
p = p / 100, q = q / 100;
if (b == 1)
{
ld ans = 0;
for (int i = 1; i <= a; i++)
{
if (i - b >= 0)dp[i] = p * (dp[i - b] + 2) + (1 - p) * (dp[i - b] + 1);
}
ans = dp[a];
ans = max(ans, a * (1.0 / (1 - q)));
printf("%.15Lf\n", ans);
return;
}
for (int i = 1; i <= a; i++)
{
if (i - b >= 0)dp[i] = max(p * (dp[i - b] + 2) + (1 - p) * (dp[i - b] + 1), q * (dp[i + 1 - b] + 1) + (1 - q) * (dp[i - b] + 1));
//cout<<i<<" "<<dp[i]<<endl;
}
printf("%.15Lf\n", dp[a]);
}