HDU 6656 Kejin Player

Kejin Player

Problem Description
Cuber QQ always envies those Kejin players, who pay a lot of RMB to get a higher level in the game. So he worked so hard that you are now the game designer of this game. He decided to annoy these Kejin players a little bit, and give them the lesson that RMB does not always work.

This game follows a traditional Kejin rule of “when you are level i, you have to pay ai RMB to get to level i+1”. Cuber QQ now changed it a little bit: “when you are level i, you pay ai RMB, are you get to level i+1 with probability pi; otherwise you will turn into level xi (xi≤i)”.

Cuber QQ still needs to know how much money expected the Kejin players needs to ``ke’’ so that they can upgrade from level l to level r, because you worry if this is too high, these players might just quit and never return again.

Input
The first line of the input is an integer t, denoting the number of test cases.

For each test case, there is two space-separated integers n (1≤n≤500 000) and q (1≤q≤500 000) in the first line, meaning the total number of levels and the number of queries.

Then follows n lines, each containing integers ri, si, xi, ai (1≤ri≤si≤109, 1≤xi≤i, 0≤ai≤109), space separated. Note that pi is given in the form of a fraction risi.

The next q lines are q queries. Each of these queries are two space-separated integers l and r (1≤l<r≤n+1).

The sum of n and sum of q from all t test cases both does not exceed 106.

Output
For each query, output answer in the fraction form modulo 109+7, that is, if the answer is PQ, you should output P⋅Q−1 modulo 109+7, where Q−1 denotes the multiplicative inverse of Q modulo 109+7.

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

Hint
Huge IO (Over 40MB)! IO optimization is preferred.

题意
从1开始升级,从i升到i+1,需要 a i a_i ai的钱, a i a_i ai必花,但是只有 p i p_i pi的概率升级到 i + 1 i+1 i+1,还有 1 − p i 1-p_i 1pi的概率降到 x i x_i xi级。 q q q次询问,求从 l l l r r r的花费的钱的期望。

题解
挺没意思的一道题,我也很绝望,先是还没想就被队友灌输了一个用 f ( i ) f(i) f(i)表示 1 − i 1-i 1i的期望的思想,然后顺着这个思路推了两个多小时,怎么想怎么不对,然后从零开始重新想
f ( i + 1 ) f(i+1) f(i+1)表示从 i i i升级到 i + 1 i+1 i+1的期望, s u m i sum_i sumi表示从 1 1 1 i i i的期望。
所以式子为
f ( i + 1 ) = p i a i + ( 1 − p i ) ( f ( i + 1 ) + a i + s u m i − s u m x i ) f(i+1)=p_ia_i+(1-p_i)(f(i+1)+a_i+sum_i-sum_{x_i}) f(i+1)=piai+(1pi)(f(i+1)+ai+sumisumxi)
s u m i + 1 = s u m i + f ( i + 1 ) sum_{i+1}=sum_i+f(i+1) sumi+1=sumi+f(i+1)
升级到 i + 1 i+1 i+1 p i p_i pi的几率只花费 a i a_i ai 1 − p i 1-p_i 1pi的几率降到 x i x_i xi,然后回升到 i i i的期望是 s u m i − s u m x i sum_i-sum_{x_i} sumisumxi,再加上从 i i i升级到 i + 1 i+1 i+1的期望和必花的 a i a_i ai

最后就是,我一开始想到了每次求概率直接求逆元,但是沙雕的 s u m i − s u m x i sum_i-sum_{x_i} sumisumxi没加 M O D MOD MOD,WA了后开始怀疑自己分数不能前面求逆元,然后写了发分数求和差,求出结果再取逆元,想想可能爆long long,还开心的弄了__int128。最后T到怀疑人生,又开始优化,果然我还是菜。

代码

#include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <ctime>
using namespace std;
#define me(x,y) memset(x,y,sizeof x)
#define MIN(x,y) (x) < (y) ? (x) : (y)
#define MAX(x,y) (x) > (y) ? (x) : (y)
#define SGN(x) ((x)>0?1:((x)<0?-1:0))
#define ABS(x) ((x)>0?(x):-(x))
// #define int __int128

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const ll maxn = 5e5+10;
const ll INF = 0x3f3f3f3f;
const int MOD = 1e9+7;
const int eps = 1e-8;

ll readll() {
  ll x = 0, w = 1;
  char ch = 0;
  while (ch < '0' || ch > '9') {  // ch 不是数字时
    if (ch == '-') w = -1;        // 判断是否为负
    ch = getchar();               // 继续读入
  }
  while (ch >= '0' && ch <= '9') {  // ch 是数字时
    x = x * 10 + (ch - '0');  // 将新读入的数字’加’在 x 的后面
    // x 是 ll 类型,char 类型的 ch 和 ’0’ 会被自动转为其对应的
    // ASCII 码,相当于将 ch 转化为对应数字
    // 此处也可以使用 (x<<3)+(x<<1) 的写法来代替 x*10
    ch = getchar();  // 继续读入
  }
  return x * w;  // 数字 * 正负号 = 实际数值
}

ll qpow(ll a,ll b,ll p){
    ll ans = 1;
    while(b){
        if(b&1) ans = ans*a%p;
        a = a*a%p;
        b >>= 1;
    }
    return ans;
}

ll r[maxn],s[maxn],x[maxn],a[maxn];
ll f[maxn],sum[maxn];
int main(){
    // ios::sync_with_stdio(false);
    ll t;t=readll();
    while(t--){
        ll n,q;
        // cin>>n>>q;
        n=readll(),q=readll();
        for(int i = 1; i <= n; ++i){
            r[i]=readll(),s[i]=readll(),x[i]=readll(),a[i]=readll();
        }
        f[0]=f[1]=0,sum[0]=sum[1]=0;
        for(int i = 1; i <= n; ++i){
            ll res = a[i]*r[i]+(s[i]-r[i])*(a[i]+sum[i]-sum[x[i]]+MOD)%MOD;
            res = (res + MOD)%MOD;
            f[i+1]=res*qpow(r[i],MOD-2,MOD)%MOD;
            sum[i+1] = sum[i]+f[i+1];
            sum[i+1] %= MOD;
        }
        for(int i = 1; i <= q; ++i){
            ll l,r;scanf("%lld%lld",&l,&r);
            printf("%lld\n",(sum[r]-sum[l]+MOD)%MOD);
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值