这是一个概率问题,需要计算在每个卡池都单抽一次的情况下,至少抽到一张想要的卡的概率。由于是概率计算,且需要输出模意义下的结果,我们需要用组合数学和模运算的知识来解决。

先想简单情况

举个例子:

  • 池子1:3 种卡,你想要 1 种 → 抽一次,抽到你想要的概率是 1/3
  • 池子2:4 种卡,你想要 1 种 → 概率 1/4

那至少一张抽到的概率 = 1 - 一张都没抽到的概率

一张都没抽到 = 池子1没抽到 * 池子2没抽到

= (2/3) * (3/4) = 6/12 = 1/2

所以至少一张抽到的概率 = 1 - 1/2 = 1/2

变成数学式子

设:

  • 分子 mol = ∏(aᵢ - bᵢ) ← 这个是“全都没抽到”的分子
  • 分母 den = ∏aᵢ ← 这个是“全都没抽到”的分母

全没抽到的概率 = mol / den

至少一张抽到的概率 = 1 - mol/den = (den - mol) / den

这就是我们要的分数(den - mol) / den

模运算转换

题目要求输出这个分数在模 1e9+7 下的值。

比如 1/2 在模运算下是 500000004,因为:

2 * 500000004 除以 1e9+7 余数是 1。

怎么转换分数到模数下

(den - mol) / den在模运算下 = (den - mol) * den⁻¹ mod MOD

这里 den⁻¹是 den 的“逆元”,就是在模 MOD 下乘上 den 得到 1 的那个数。

逆元计算公式den⁻¹ = den^(MOD-2) mod MOD(费马小定理,MOD 是质数)

def inv(num):

return pow(num,MOD-2,MOD)

也就是以上代码(c++版需要手动实现快速幂)

总结

1 减去(每个池子都没抽到想要的概率)

然后把这个分数用模运算的形式输出。

代码就是把上面公式翻译成乘法 + 取模 + 用快速幂求一次逆元。

示例代码

import sys
input=sys.stdin.readline
n=int(input())
MOD=10**9+7
a=list(map(int,input().split()))
b=list(map(int,input().split()))

mol=1
den=1
def inv(num):
    return pow(num,MOD-2,MOD)
    
for i in range(n):
    mol*=a[i]-b[i]
    den*=a[i]
    mol%=MOD
    den%=MOD
print((den-mol)*inv(den)%MOD)
#include <iostream>
#include <vector>
using namespace std;

const int MOD = 1e9 + 7;

long long mod_pow(long long a, long long b, long long mod) {
    long long res = 1;
    while (b) {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}

long long inv(long long num) {
    return mod_pow(num, MOD - 2, MOD);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int n;
    cin >> n;
    
    vector<long long> a(n), b(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> b[i];
    }
    
    long long mol = 1, den = 1;
    for (int i = 0; i < n; i++) {
        long long diff = (a[i] - b[i]) % MOD;
        if (diff < 0) diff += MOD; 
        mol = mol * diff % MOD;
        den = den * (a[i] % MOD) % MOD;
    }
    
    long long result = (den - mol) % MOD;
    if (result < 0) result += MOD;
    result = result * inv(den) % MOD;
    
    cout << result << endl;
    
    return 0;
}