Bowcraft(题解+代码)

Bowcraft
——杭电第二场多校1009-Bowcraft

题意

:
有一把弓,初始等级为 0 0 0 ,商店提供一本升级书,在使用这本升级书时,有 a A \frac{a}{A} Aa 的概率将弓提升 1 1 1 级,如果升级失败,就有 b B \frac{b}{B} Bb 的概率(前提是使用了这本书并且升级失败)使这把弓的等级降为 0 0 0 ,当你从商店购买一本升级书时,商店系统会在 [ 0 , A − 1 ] [0,A-1] [0,A1] 中生成一个随机数 a a a ,在 [ 0 , B − 1 ] [0,B-1] [0,B1] 中生成一个随机数 b b b ,在购买了升级书后,你需要确定是否使用这本书,问:当你使用最佳策略时,将弓从 0 0 0 级升到 K K K 级所需要购买的升级书数量的数学期望是多少。

T T T 组数据,每次输入一组 K , A , B K,A,B K,A,B 其中 ( T ≤ 10 , 1 ≤ K ≤ 1000 , 2 ≤ A , B ≤ 100 ) (T\le 10,1\le K \le 1000,2\le A,B \le 100) (T10,1K1000,2A,B100)

做法:

​ 考虑使用 d p dp dp 解决该问题, d p [ i ] dp[i] dp[i] 表示将弓从 0 0 0 级升到 K K K 级所需要购买升级书数量的数学期望,为了方便表达,我们令 α = a A \alpha=\frac{a}{A} α=Aa ,令 β = b B \beta=\frac{b}{B} β=Bb .

​ 假设当前的等级为 i i i ,买了一本随机数为 ( a , b ) (a,b) (a,b) 的升级书,我们对这本书有两种处理方法:

1 如果我们选择使用这本书升级,那么将弓升到 i + 1 i+1 i+1 级的期望是 d p [ i ] + 1 + ( 1 − α ) β ⋅ d p [ i + 1 ] + ( 1 − α ) ( 1 − β ) ⋅ ( d p [ i + 1 ] − d p [ i ] ) dp[i]+1+(1-\alpha) \beta \cdot dp[i+1]+(1-\alpha)(1-\beta) \cdot (dp[i+1]-dp[i]) dp[i]+1+(1α)βdp[i+1]+(1α)(1β)(dp[i+1]dp[i]) ,我们先来解释一下这个式子:

d p [ i ] + 1 dp[i]+1 dp[i]+1 :因为我们确定要使用这本书,所以将弓升到 i + 1 i+1 i+1 的期望一定会先在 d p [ i ] dp[i] dp[i] 的基础上加 1 1 1 ,然后,

( 1 − α ) β ⋅ d p [ i + 1 ] (1-\alpha) \beta \cdot dp[i+1] (1α)βdp[i+1] :这里 ( 1 − α ) β (1-\alpha) \beta (1α)β 为升级失败并触发等级降为 0 0 0 情况的概率,当发生这种情况时,需要重新将弓升级到 i + 1 i+1 i+1 级才能满足要求,故这里需要乘 d p [ i + 1 ] dp[i+1] dp[i+1] ,也就是乘以将弓升级到 i + 1 i+1 i+1 级的期望。

( 1 − α ) ( 1 − β ) ⋅ ( d p [ i + 1 ] − d p [ i ] ) (1-\alpha)(1-\beta) \cdot (dp[i+1]-dp[i]) (1α)(1β)(dp[i+1]dp[i]) :这里前面 ( 1 − α ) ( 1 − β ) (1-\alpha)(1-\beta) (1α)(1β) 是指弓升级失败但没有触发等级降为零事件的概率,发生这种事件的次数为升级到 i + 1 i+1 i+1 级所需次数与升级到 i i i 级所需次数之差,即使用了升级书但弓的等级不变的次数。

2 如果我们选择不使用这本书升级,那么将弓升到 i + 1 i+1 i+1 级的期望是 d p [ i + 1 ] + 1 dp[i+1]+1 dp[i+1]+1 ,意思是如果不使用这本书,升级到 i + 1 i+1 i+1 的期望依旧要加 1 1 1

​ 因此我们可以得到如下的 d p dp dp 方程:
d p [ i + 1 ] = 1 A B ∑ a , b m i n { d p [ i + 1 ] + 1 , d p [ i ] + 1 + ( 1 − α ) β ⋅ d p [ i + 1 ] + ( 1 − α ) ( 1 − β ) ⋅ ( d p [ i + 1 ] − d p [ i ] ) } dp[i+1]= \frac{1}{AB} \sum_{a,b} min \left \{ dp[i+1]+1, dp[i]+1+(1-\alpha) \beta \cdot dp[i+1]+(1-\alpha)(1-\beta) \cdot (dp[i+1]-dp[i])\right \} dp[i+1]=AB1a,bmin{dp[i+1]+1,dp[i]+1+(1α)βdp[i+1]+(1α)(1β)(dp[i+1]dp[i])}

m i n min min 的含义是,对本书进行判断,若使用当前这本书的期望大于不使用当前这本书的期望,则不使用。

对于当前的等级 i i i 和一本书 ( a , b ) (a, b) (a,b) ,如果要使用这本书,那么升到 i + 1 i + 1 i+1 级,不使用的期望 ≥ \ge 使用的期望

d p [ i + 1 ] + 1 ≥ d p [ i ] + 1 + ( 1 − α ) β ⋅ d p [ i + 1 ] + ( 1 − α ) ( 1 − β ) ⋅ ( d p [ i + 1 ] − d p [ i ] ) dp[i+1]+1 \ge dp[i]+1+(1-\alpha) \beta \cdot dp[i+1]+(1-\alpha)(1-\beta) \cdot (dp[i+1]-dp[i]) dp[i+1]+1dp[i]+1+(1α)βdp[i+1]+(1α)(1β)(dp[i+1]dp[i])

化简为: d p [ i + 1 ] ≥ d p [ i ] ⋅ α + β − α β α dp[i+1] \ge dp[i] \cdot \frac{\alpha + \beta -\alpha \beta}{\alpha} dp[i+1]dp[i]αα+βαβ

​ 从上式可见, α + β − α β α \frac{\alpha + \beta -\alpha \beta}{\alpha} αα+βαβ 值较小的升级书更容易被使用,即 β ( 1 − α ) α \frac{\beta (1-\alpha)}{\alpha} αβ(1α) 值更小的升级书更容易被使用,因此我们可以先对 A ∗ B A*B AB 本书的 β ( 1 − α ) α \frac{\beta (1-\alpha)}{\alpha} αβ(1α) 值进行排序预处理,假设有 t t t 本书符合使用条件,我们就使用 β ( 1 − α ) α \frac{\beta (1-\alpha)}{\alpha} αβ(1α) 值前 t t t 小的书,其他的书不使用,那么有:

A B ⋅ d p [ i + 1 ] = ( A B − t ) ⋅ ( d p [ i + 1 ] + 1 ) + ∑ a , b ∈ ( 前 t 小 ) d p [ i ] + 1 + ( 1 − α ) β ⋅ d p [ i + 1 ] + ( 1 − α ) ( 1 − β ) ⋅ ( d p [ i + 1 ] − d p [ i ] ) AB\cdot dp[i+1]=(AB-t)\cdot (dp[i+1]+1)+\sum_{a,b\in (前t小)}dp[i]+1+(1-\alpha) \beta \cdot dp[i+1]+(1-\alpha)(1-\beta) \cdot (dp[i+1]-dp[i]) ABdp[i+1]=(ABt)(dp[i+1]+1)+a,b(t)dp[i]+1+(1α)βdp[i+1]+(1α)(1β)(dp[i+1]dp[i])

化简得 d p [ i + 1 ] = A B + d p [ i ] ⋅ ∑ a , b ∈ ( 前 t 小 ) α + β − α β t − ∑ a , b ∈ ( 前 t 小 ) 1 − α dp[i+1]=\frac{AB+dp[i] \cdot \sum_{a,b\in (前t小)} \alpha + \beta -\alpha \beta}{t-\sum_{a,b\in (前t小)}1- \alpha } dp[i+1]=ta,b(t)1αAB+dp[i]a,b(t)α+βαβ

计算:

​ 将符合条件的升级书 ( a , b ) (a,b) (a,b) β ( 1 − α ) α \frac{\beta (1-\alpha)}{\alpha} αβ(1α) 值从小到大求和,用 s u m 1 sum1 sum1 求和符合条件的 α + β − α β \alpha + \beta -\alpha \beta α+βαβ ,即 s u m 1 = ∑ i ∈ t α i + β i − α i β i sum1=\sum_{i\in t} \alpha_i + \beta_i -\alpha_i \beta_i sum1=itαi+βiαiβi ,用 s u m 2 sum2 sum2 求和符合条件的 1 − α 1-\alpha 1α ,即 s u m 2 = ∑ i ∈ t α i sum2=\sum_{i\in t} \alpha_i sum2=itαi 。遍历排好序后的 ( α , β ) (\alpha,\beta) (α,β) 对每个 i i i 进行一次判断,判断加上这一对 ( α , β ) (\alpha,\beta) (α,β) d p [ i + 1 ] dp[i+1] dp[i+1] 的预计期望是否变小,若不变小则退出循环,更新 d p [ i + 1 ] dp[i+1] dp[i+1] 的最小值,按照同样的方法递推得到并输出 d p [ K ] dp[K] dp[K]

​ 由于每次递推得到 d p [ i + 1 ] dp[i+1] dp[i+1] 的复杂度为 O ( A B ) O(AB) O(AB) ,总复杂度为 O ( K A B ) O(KAB) O(KAB).

代码:

#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
#define f first
#define s second
using namespace std;
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int t;cin>>t;
    while(t--)
    {
        int k,a1,b1;
        cin>>k>>a1>>b1;
        double a=a1,b=b1;
        vector<double> dp(k+1);
        dp[0]=0;//弓箭初始为0级,期望为0
        vector<pair<double,double> > ab;
        for(int i=1;i<a1;i++)
        {
            for(int j=0;j<b1;j++)
            {
                ab.emplace_back((double)i/a,(double)j/b);//预处理求出a/A 与 b/B
            }
        }
        auto cmp = [&](pair<double,double> aa1,pair<double,double> bb1)//从小到大排序
        {
            double af1=aa1.f,bt1=aa1.s;
            double af2=bb1.f,bt2=bb1.s;
            return bt1*(1.0-af1)/af1<bt2*(1.0-af2)/af2;
        };
        sort(ab.begin(),ab.end(),cmp);

        for(int i=0;i<k;i++)//k次递推得到dp[K]
        {
            double tt=0,s1=0,s2=0;
            double ab1=a*b;
            for(int j=0;j<ab.size();j++)
            {
                double af=ab[j].f;
                double bt=ab[j].s;
                double t1=s1+af+bt-af*bt;
                double t2=s2+1-af;
                if((ab1+dp[i]*t1)/(tt+1-t2)<=(ab1+dp[i]*s1)/(tt-s2))
                {
                    s1=t1;
                    s2=t2;
                    tt+=1;
                }
            }
            dp[i+1]=(ab1+dp[i]*s1)/(tt-s2);
        }
        cout<<fixed<<setprecision(3)<<dp[k]<<endl;//注意保留三位小数
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值