51Nod1667 概率好题 <容斥+计数>

Problem

概率好题

Time  Limit:  4  Sec\mathrm{Time\;Limit:\;4\;Sec}
Memory  Limit:  131072  KB\mathrm{Memory\;Limit:\;131072\;KB}

Description

甲乙进行比赛,他们各有k1,k2k_1,k_2个集合[Li,Ri][L_i,R_i],每次随机从他们拥有的每个集合中都取出一个数。
S1=甲取出的数S_1=\sum甲取出的数S2S_2同理。若S1>S2S_1>S_2甲胜;若S1=S2S_1=S_2平局;否则乙胜。
分别求出甲胜、平局、乙胜的概率。
(显然这个概率是有理数,记为pq\frac{p}{q},则输出答案为pqmod109+7\frac{p}{q}\bmod{10^9+7}(逆元)
注意:多组数据

Input

一个数,数据组数(T5)(T\le5)
对于每组数据 输入顺序为

1
2
k1 L1 R1 ... Lk1 Rk1
k2 L1 R1 ... Lk2 Rk2

(k1,k28,1LR107)(k_1,k_2\le8,1\le L\le R\le10^7)

Output

甲胜、平局、乙胜的概率。

Input示例

1
2
3
1
1 1 2
1 1 4

Output示例

1
125000001 250000002 625000005

标签:容斥 计数DP

Solution

设甲取的数为R1,1x1,R1,2x2,,R1,k1xk1R_{1,1}-x_1,R_{1,2}-x_2,\cdots,R_{1,k_1}-x_{k_1},乙取的数为L2,1+y1,L2,2+y2,,L2,k2+yk2L_{2,1}+y_1,L_{2,2}+y_2,\cdots,L_{2,k_2}+y_{k_2}。显然有xi[0,R1,iL1,i]x_i\in[0,R_{1,i}-L_{1,i}]yi[0,R2,iL2,i]y_i\in[0,R_{2,i}-L_{2,i}]

以甲胜为例,有

i=1k1R1,ii=1k1xi>i=1k2yi+i=1k2L2,i\sum_{i=1}^{k_1}R_{1,i}-\sum_{i=1}^{k_1}x_i>\sum_{i=1}^{k_2}y_i+\sum_{i=1}^{k_2}L_{2,i}

移项得

i=1k1xi+i=1k2yi<C\sum_{i=1}^{k_1}x_i+\sum_{i=1}^{k_2}y_i<C

其中C=i=1k1R1,ii=1k2L2,iC=\sum_{i=1}^{k_1}R_{1,i}-\sum_{i=1}^{k_2}L_{2,i}
加入变量t[0,]t\in[0,\infty],使得有

i=1k1xi+i=1k2yi+k=C1\sum_{i=1}^{k_1}x_i+\sum_{i=1}^{k_2}y_i+k=C-1

答案变成这个方程解的个数。

由于前k1+k2k_1+k_2个变量都有上限制约,我们可以容斥一下,求有至少pp个变量超过上限时的解的个数。
pp个变量一定呈lim+xlim+x'的形式,其中limlim为上限,x[0,]x'\in[0,\infty]
这样的解的个数就是将C1limC-1-\sum lim拆为k1+k2+1k_1+k_2+1个数的方案数,显然由隔板法这个值为

(C1lim+k1+k2k1+k2)\binom{C-1-\sum lim+k_1+k_2}{k_1+k_2}

设这样求出的至少pp个变量超过上限时的解的个数为SpS_p,那么甲胜的情况数为

ans=i=0n(1)iSians=\sum_{i=0}^{n}(-1)^iS_i

同理可以求出平局的情况,求出两者的概率,用11减去即可得到乙胜的概率。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <bits/stdc++.h>
#define P 1000000007
using namespace std;
typedef long long lnt;
template <class T> inline void read(T &x) {
x = 0; int c = getchar(), f = 1;
for (; !isdigit(c); c = getchar()) if (c == 45) f = -1;
for (; isdigit(c); c = getchar()) (x *= 10) += f*(c-'0');
}
int n, n1, n2, r[20];
lnt s, sa, sb, sc; bool mrk[20];
lnt inv(lnt x) {
lnt ret = 1;
for (int k = P-2; k; k >>= 1, x = x*x%P)
if (k&1) ret = ret*x%P;
return ret;
}
lnt C(lnt n, int m) {
lnt ret = 1;
for (int i = 1; i <= m; i++) ret = ret*(n-i+1)%P;
for (int i = 1; i <= m; i++) ret = ret*inv(i)%P;
return ret;
}
void upd(lnt &res) {
lnt ss = s, f = 1;
for (int i = 1; i <= n; i++)
if (mrk[i]) ss -= (r[i]+1), f *= -1;
if (ss >= 0) res = (res+f*C(ss+n, n)+P)%P;
}
void DFS(int stp, lnt &res) {
if (s < 0) {res = 0; return;}
if (stp > n) {upd(res); return;}
mrk[stp] = true, DFS(stp+1, res);
mrk[stp] = false, DFS(stp+1, res);
}
int main() {
int T; read(T);
while (T--) {
read(n1), s = sa = sb = sc = 0;
for (int i = 1, L, R; i <= n1; i++)
read(L), read(R), r[i] = R-L, s += R;
read(n2);
for (int i = 1, L, R; i <= n2; i++)
read(L), read(R), r[i+n1] = R-L, s -= L;
n = n1+n2, r[n+1] = 0x7f7f7f7f;
s--, DFS(1, sa), s++, DFS(1, sc), sc = (sc-sa+P)%P;
for (int i = 1; i <= n; i++) sa = sa*inv(r[i]+1)%P;
for (int i = 1; i <= n; i++) sc = sc*inv(r[i]+1)%P;
sb = (1-sa-sc+P+P)%P, printf("%lld %lld %lld\n", sa, sc, sb);
}
return 0;
}