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 }