51nod 1667 概率好题

甲乙进行比赛。

他们各有k1,k2个集合[Li,Ri](整数集合)

每次随机从他们拥有的每个集合中都取出一个数

S1=sigma甲取出的数,S2同理

若S1>S2甲胜 若S1=S2平局 否则乙胜

分别求出甲胜、平局、乙胜的概率。

(显然这个概率是有理数,记为p/q,则输出答案为(p/q)%(1e9+7))(逆元)

k1,k2<=8,1<=L<=R<=10^7

这是一个假的概率题,统计合法方案数后除以总方案数即可

以甲胜为例,即求$\sum\limits_{i=1}^{k_1}X_i \gt \sum\limits_{i=1}^{k_2}Y_i$的非负整数解个数,其中$L_{1,i} \le X_i \le R_{1,i},L_{2,i} \le Y_i \le R_{2,i}$

设$0 \le x_i \le R_{1,i}-L_{1,i},0 \le y_i \le R_{2,i}-L_{2,i}$

构造$X_i=R_{1,i}-x_i,Y_i=L_{2,i}+y_i$

则$\sum\limits_{i=1}^{k_1}R_{1,i}-x_i \gt \sum\limits_{i=1}^{k_2}L_{2,i}+y_i$

即$\sum\limits_{i=1}^{k_1}x_i + \sum\limits_{i=1}^{k_2}y_i \lt \sum\limits_{i=1}^{k_1}R_{1,i}-\sum\limits_{i=1}^{k_2}L_{2,i}$

现在将小于变为成小于等于(即不等式右侧减一),同时加上辅助变量$k$,将不等式变为等式,其中$k \ge 0$

即$\sum\limits_{i=1}^{k_1}x_i + \sum\limits_{i=1}^{k_2}y_i + k = \sum\limits_{i=1}^{k_1}R_{1,i}-\sum\limits_{i=1}^{k_2}L_{2,i}-1$

在学习插板法的时候,有一个经典例题,即$\sum\limits_{i=1}^{n} x_i=b$的非负整数解的个数,即$C(b+n-1,n-1)$,可以理解为将$b$个$1$之间插入$n-1$个插板,同时一个插板可以不用

但是这个不定方程的每个变量都有一个上限的限制,看到变量的个数不太多,可以用容斥来解决

即方案数=0个变量满足条件的方案-1个变量满足条件的方案+...+(-1)n个变量满足条件的方案

不满足条件就相当于将$x_i$变为$x_i+R_{1,i}-L_{1,i}+1$

知识点覆盖面广;题目新颖,注重考查能力;给出题人点赞

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int p = 1e9 + 7, N = 20;
 4 typedef long long ll;
 5 int pw(int a, int b) {
 6     int r = 1;
 7     for( ; b ; b >>= 1, a = 1ll * a * a % p) if(b & 1) r = 1ll * r * a % p;
 8     return r;
 9 }
10 int calc(int n, ll b) {
11     if(b < 0) return 0;
12     int r = 1;
13     for(int i = 1 ; i < n ; ++ i) r = 1ll * r * pw(i, p - 2) % p;
14     for(int i = 1 ; i < n ; ++ i) r = 1ll * r * (b + i) % p;
15     return r;
16 }
17 int cnt[1 << 20], total, k1, k2, L1[N], R1[N], L2[N], R2[N];
18 int getans(int ty) {
19     ll b = -1;
20     if(ty == 1) {
21         for(int i = 1 ; i <= k1 ; ++ i) b += R1[i];
22         for(int i = 1 ; i <= k2 ; ++ i) b += -L2[i];
23     } else {
24         for(int i = 1 ; i <= k2 ; ++ i) b += R2[i];
25         for(int i = 1 ; i <= k1 ; ++ i) b += -L1[i];
26     }
27     int ans = 0;
28     for(int s = 0 ; s < 1 << (k1 + k2) ; ++ s) {
29         int sig = (cnt[s] & 1) ? -1 : 1;
30         ll B = b;
31         for(int i = 1 ; i <= k1 ; ++ i) {
32             if((s >> (i - 1)) & 1) {
33                 B -= R1[i] - L1[i] + 1;
34             }
35         }
36         for(int i = 1 ; i <= k2 ; ++ i) {
37             if((s >> (k1 + i - 1)) & 1) {
38                 B -= R2[i] - L2[i] + 1;
39             }
40         }
41         ans = (ans + 1ll * sig * calc(k1 + k2 + 1, B)) % p;
42     }
43     return (1ll * ans % p + p) % p * total % p;
44 }
45 void sol() {
46     total = 1;
47     scanf("%d", &k1);
48     for(int i = 1 ; i <= k1 ; ++ i) {
49         scanf("%d%d", &L1[i], &R1[i]);
50         total = (1ll * total * pw(R1[i] - L1[i] + 1, p - 2)) % p;
51     }
52     scanf("%d", &k2);
53     for(int i = 1 ; i <= k2 ; ++ i) {
54         scanf("%d%d", &L2[i], &R2[i]);
55         total = (1ll * total * pw(R2[i] - L2[i] + 1, p - 2)) % p;
56     }
57     int ans1 = getans(1), ans3 = getans(3), ans2 = ((1 - ans1 - ans3) % p + p) % p;
58     printf("%d %d %d\n", ans1, ans2, ans3);
59 }
60 int main() {
61     for(int i = 1 ; i < (1 << 20) ; ++ i) cnt[i] = cnt[i >> 1] + (i & 1);
62     int T; scanf("%d", &T);
63     while(T --) sol();
64 }
51nod 1667 概率好题

 

posted @ 2018-08-07 22:35  KingSann  阅读(336)  评论(0编辑  收藏  举报