【2019杭电多校第七场1011=HDU6656】Kejin Player(期望dp+递推+逆元)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=6656

题目:


若当前等级为i,花掉a_i元有p的概率升级到等级i+1,有1-p的概率降到等级x_i (1≤x_i≤i)

问从等级l升级的等级r需要的花费的期望值

输入:测试样例t,n个等级,q个询问,每个等级给出对应的p_i,x_i,a_i,其中p_i\frac{r_i}{s_i}表示,每个询问给出l,r。注意可以从等级n升级到等级n+1

Sample Input

1 
3 2
1 1 1 2 
1 2 1 3 
1 3 3 4 
1 4 
3 4

Sample Output

22

12

 

解题思路:


dp[i]表示从等级1升级到等级i花费的期望值

i\overset{p_i}{\rightarrow}(i+1)

i\overset{1-p_i}{\rightarrow}x_i

无论转化成哪个等级都需要花费a_i元,若转化为等级x_i,那么x_i也能转化为i+1

因为每次只能升级一步,且x_i ≤ i+1,所以在从等级1升级到等级i+1的过程中一定会经过等级x_i,根据期望dp减法可知:

dp[x_i\rightarrow i+1]=dp[i+1]-dp[x_i]

1\rightarrow i+1等价于(1\rightarrow i) + (i\rightarrow i+1),其中(i\rightarrow i+1)=a_i+(1-p_i)*(dp[i+1]-dp[x_i])

可以推出如下递推式:

dp[i+1]=dp[i] +a_i+ (1-p_i)*(dp[i+1]-dp[x_i])

化简有:dp[i+1]=\frac{dp[i]+a_i-(1-p_i)*dp[x_i]}{p_i},在计算时,因为p_i是分数,化成小数会存在误差,故把它们直接转化成逆元来计算

 

ac代码:


#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
struct node{
    ll r, s, x, a;
}d[maxn];
ll dp[maxn];
ll n, q, t;
int L, R;
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;
}
ll getInv(ll a, ll b) // a/b
{
    return (a * qpow(b, mod - 2)) % mod;
}
int main() {
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld %lld", &n, &q);
        for(int i = 1; i <= n; i++)
            scanf("%lld %lld %lld %lld", &d[i].r, &d[i].s, &d[i].x, &d[i].a);
        dp[1] = 0;
        for(int i = 1; i <= n; i++)
        {
            ll p1 = getInv(d[i].s - d[i].r, d[i].s);//1-(p的逆元)= (1-p)的逆元
            ll p2 = getInv(d[i].s, d[i].r);//(1/p)的逆元
            dp[i + 1] = (p2 * ((d[i].a + dp[i]) % mod - (p1 * dp[d[i].x]) % mod + mod) % mod) % mod;
        }
        int L,R;
        for(int i = 1; i <= q; i++)
        {
            scanf("%d%d",&L, &R);
            printf("%lld\n",(dp[R] - dp[L] + mod) % mod);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值