杭电多校第七场 1011 Kejin Player HDU(6656)

杭电多校第七场 1011 Kejin Player

题意:给你N行,代表从i级有花费a[i]元的r[i]/s[i]的概率达到i+1级,剩下的概率中可能会到达x[i]级。然后询问从L级到R级的花费会是多少。

闲话:这场也是真自闭了,开始先去看fianl exam去了,然后疯狂自闭近两小时,最后看最后一题A了很多人就去看看了,开始想线段树+概率DP,百度了很久学习这个东西,然后突然发现其实递推就可以了,类似前缀和,然后经过一系列过程,过了。我和我的队友接着自闭在1001。。。。。

题解:递推。
A:关键公式:f[i] = f[i-1] +a[i] +(1-p)*(f[i] - f[x])
B:公式意义:f[i]代表了从第一级到第i级的花费,那么转移公式,f[i]为上一次的花费f[i-1]+a[i],即充钱后成功升级,然后(1-p)*(f[i] - f[x]),升级失败,那么要升级到i级就要从x级升级到i级,然后花费就是f[i]-f[x]然后乘上概率,最后都加上就是式子了。
C:最后解方程把f[i]都移动到左边,就可以递推了。

#include<cstdio>
#include<string>
#include<algorithm>
#include<iostream>
#include<string.h>
#define inv(p) pown(p, mo - 2)
using namespace std;
const int mx = 5e5 + 7;
typedef long  long ll;
const ll mo = 1e9 + 7;
ll n, q;
ll r[mx], s[mx], x[mx], a[mx], f[mx];
ll pown(ll x, ll n) {
    ll res = 1;
    while (n > 0) {
        if (n % 2 == 1) {
            res = (res*x) % mo;
            res %= mo;
        }
        x = x * x%mo;
        n >>= 1;
    }
    return res;
}
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%lld%lld", &n, &q);
        f[1] = 0;
        memset(f, 0, sizeof(f));
        for (int i = 1; i <= n; i++) {
            scanf("%lld%lld%lld%lld", &r[i], &s[i], &x[i], &a[i]);
        }
        for (int i = 1; i <= n ; i++) {
            f[i + 1] = (s[i] * (f[i] + a[i] - f[x[i]]+mo) % mo*inv(r[i]) % mo + f[x[i]] % mo) % mo;
            f[i + 1] %= mo;
        }
        for (int i = 1; i <= q; i++) {
            ll L, R;
            scanf("%lld%lld", &L, &R);
            printf("%lld\n", (f[R] - f[L] + mo) % mo);
        }
    }
    return 0;
}

你可能感兴趣的:(思维,DP)