Problem Description
“看似随机,实则早已注定”——光羽
度度熊有n个随机变量 x1,x2,...,xn x 1 , x 2 , . . . , x n 。给定区间 [l1,r1],...,[ln,rn] [ l 1 , r 1 ] , . . . , [ l n , r n ] ,变量 xi x i 的值会等概率成为区间 [li,ri] [ l i , r i ] 中的任意一个整数。
显然这n个随机变量的值会有一共 ∏ni=1(ri−li+1) ∏ i = 1 n ( r i − l i + 1 ) 种情况,且每种情况出现的概率为 ∏ni=11ri−li+1 ∏ i = 1 n 1 r i − l i + 1
对于某种情况,令 h=maxx1,x2,...,xn h = m a x x 1 , x 2 , . . . , x n ,定义这种情况的权值为: ∏ni=1(h−xi+1) ∏ i = 1 n ( h − x i + 1 ) .
度度熊想知道权值的期望是多少?请将答案对109+7取模后输出。
PS:不清楚期望是啥?为什么不问问神奇的百度呢?
Input
第一行一个数,表示数据组数T。
每组数据第一行一个整数n;接下来n行,每行两个数,表示li和ri。
数据组数T=100,满足:
−1≤n≤100
−
1
≤
n
≤
100
−1≤li≤ri≤104
−
1
≤
l
i
≤
r
i
≤
10
4
其中70%的数据满足ri≤100。
Output
每组数据输出一行,每行仅包含一个数,表示期望。
假设答案为pq,请输出p×q−1 mod 109+7,此处q−1为q的逆元。
Sample Input
2
3
2 5
2 4
2 5
3
1 1
2 3
1 1
Sample Output
875000012
500000010
Hint
第二组数据的解释:序列只有两种情况(1,2,1)和(1,3,1),权值分别为2*1*2=4和3*1*3=9,答案为(4+9)/2,在模域下为500000010。
分析: 因为是要求期望,所以是每一种情况概率乘相对应的权值,求和就行了。然后我们可以发现每一种情况的概率都是一样的,所以我们只需要算出所有情况的总权值之和就行了。但是如果按照题意给的公式求解,时间肯定爆炸,所以我们要优化这个公式,我们可以枚举h,对于同一个h来说
(∏li≤h≤ri∑hxi=lih−xi+1)(∏ri<h∑rixi=lih−xi+1)
(
∏
l
i
≤
h
≤
r
i
∑
x
i
=
l
i
h
h
−
x
i
+
1
)
(
∏
r
i
<
h
∑
x
i
=
l
i
r
i
h
−
x
i
+
1
)
这个公式可以计算出包含最大值为h的所有情况,但是我们想要的是最大值为h的总权值,所以我们可以减掉小于h的那部分就可以了。
优化后的公式还是蛮不好想的,所以我抽象出来了一个简单的问题,把这个搞懂了,应该就可以理解上面的公式:
3 种物体,每种物体有3个(每个物体都有自己独特的权值),你每次必须要从一种物体里面挑选一个, 这样会有3*3*3种选择,每种选择的权值定义为:所选的三个物体的权值之和.。现在求所有选择的总权值之和。
a3b3c3
a
3
b
3
c
3
a2b2c2
a
2
b
2
c
2
a1b1c1
a
1
b
1
c
1
最暴力的一种就是3*3*3的复杂度求解。
另外一种呢,所有情况的总权值之和为:
(a1+a2+a3)∗(b1+b2+b3)∗(c1+c2+c3)
(
a
1
+
a
2
+
a
3
)
∗
(
b
1
+
b
2
+
b
3
)
∗
(
c
1
+
c
2
+
c
3
)
,为什么是这个公式呢? 应该很容易理解吧,仔细想想?
代码
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <list>
#include <string>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define rep(i, l, r) for(int i = l; i < r; i++)
#define per(i, r, l) for(int i = r; i >= l; i--)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int N = (int) 1e5 + 11;
const int M = (int) 1e6 + 11;
const int MOD = (int) 1e9 + 7;
const double EPS = (double) 1e-9;
const double PI = (double)acos(-1.0);
const int INF = (int) 0x3f3f3f3f;
const ll INFF = (ll) 0x3f3f3f3f3f3f3f3f;
void read(int &x){
char ch = getchar(); x = 0;
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
}
/*-----------------------------------------------------------------------------------*/
int l[N], r[N];
int Pow(int a, int b, int c = MOD){
int s = 1; a %= c;
while(b){
if(b & 1) s = s * 1ll * a % c;
b >>= 1;
a = a * 1ll * a % c;
}
return s;
}
int inv2 = Pow(2, MOD - 2);
int GetSum(int l, int r){ // 公差为1,首项为l尾项是r的 等差数列的和
if(l > r) return 0;
return (l + r) * 1ll * (r - l + 1) % MOD * inv2 % MOD;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int T; scanf("%d", &T);
while(T--){
int n; scanf("%d", &n);
int mxL = 0, mxR = 0, prod = 1;
rep(i, 0, n) {
scanf("%d%d", l + i, r + i);
mxL = max(mxL, l[i]); mxR = max(mxR, r[i]); // 找到枚举h的下界和上界
prod = prod * 1ll * (r[i] - l[i] + 1) % MOD; // 需要求分母的逆元
}
//cout << mxL << " " << mxR << " " << prod <<" \n";
int ans = 0;
rep(h, mxL, mxR + 1){
int sum1 = 1, sum2 = 1;
rep(i, 0, n){
int le = l[i]; int ri = min(r[i], h);
sum1 = sum1 * 1ll * GetSum(h - ri + 1, h - le + 1) % MOD;
ri = min(r[i], h - 1);
sum2 = sum2 * 1ll * GetSum(h - ri + 1, h - le + 1) % MOD;
// cout << sum1 << " " << sum2 <<"\n";
}
if(h > mxL) sum1 = (sum1 - sum2 + MOD) % MOD; // 第一项不用减
ans += sum1; if(ans >= MOD) ans -= MOD;
}
//cout << ans << " " << Pow(prod, MOD - 2) << " " <<"\n";
ans = ans * 1ll * Pow(prod, MOD - 2) % MOD;
printf("%d\n", ans);
}
return 0;
}