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
1−pi的概率降到
x
i
x_i
xi级。
q
q
q次询问,求从
l
l
l到
r
r
r的花费的钱的期望。
题解
挺没意思的一道题,我也很绝望,先是还没想就被队友灌输了一个用
f
(
i
)
f(i)
f(i)表示
1
−
i
1-i
1−i的期望的思想,然后顺着这个思路推了两个多小时,怎么想怎么不对,然后从零开始重新想
用
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+(1−pi)(f(i+1)+ai+sumi−sumxi)
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
1−pi的几率降到
x
i
x_i
xi,然后回升到
i
i
i的期望是
s
u
m
i
−
s
u
m
x
i
sum_i-sum_{x_i}
sumi−sumxi,再加上从
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} sumi−sumxi没加 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;
}