A 题:逆元、模拟、状态压缩、概率论
题意
有八个独立的数位显示器,每个显示器的每个二极管被点亮的概率为 pi,二极管之间互相独立,显示器之间也相互独立。求分别显示出两个四位合法数字,且数字之和等于输入的常数 C 的概率。
需满足以下条件:
- 最终所有显示器均有灯管被点亮(不能全灭)。
- 最终所有显示器显示的结果均为合法数字。
- 第一排拼接的十进制数记作 A,第二排拼接的十进制数记作 B,满足 A + B = C(允许前导零)。
思路
由于显示器完全独立,可先计算每个显示器表示 0-9 的概率,进而通过独立概率乘积计算特定数字的概率。枚举 0 到 C 的所有数字组合,计算概率和。
计算 0-9 的概率需使用状态压缩技巧。将需要点亮的灯管定为 1,不需要的定为 0,预存 0-9 的二进制状态表。
整个过程涉及取模运算,除法需用乘法逆元代替。
分数取模原理
在模数 m 为质数且 b 不是 m 倍数的情况下,根据费马小定理: a / b mod m = a * (b^(m-2)) mod m 即 1/b = b^(m-2) mod m。这避免了小数精度问题。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
int c;
int p[8];
int S[10];
void init() {
S[0] = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6);
S[1] = (1 << 2) | (1 << 5);
S[2] = (1 << 0) | ( << ) | ( << ) | ( << ) | ( << );
S[] = ( << ) | ( << ) | ( << ) | ( << ) | ( << );
S[] = ( << ) | ( << ) | ( << ) | ( << );
S[] = ( << ) | ( << ) | ( << ) | ( << ) | ( << );
S[] = ( << ) | ( << ) | ( << ) | ( << ) | ( << ) | ( << );
S[] = ( << ) | ( << ) | ( << );
S[] = ( << ) | ( << ) | ( << ) | ( << ) | ( << ) | ( << ) | ( << );
S[] = ( << ) | ( << ) | ( << ) | ( << ) | ( << ) | ( << );
}
{
ans = ;
a = a % mod;
(; b; b >>= ) {
(b & ) ans = (ans * a) % mod;
a = (a * a) % mod;
}
ans;
}
inv100 = (, mod - , mod);
{
cin >> c;
( i = ; i < ; i++) {
cin >> p[i];
p[i] = (p[i] * inv100) % mod;
}
;
( i = ; i < ; i++) {
( j = ; j < ; j++) {
((S[i] >> j) & ) {
digit[i] = (digit[i] * p[j]) % mod;
} {
not_p = ( - p[j] + mod) % mod;
digit[i] = (digit[i] * not_p) % mod;
}
}
}
calc = [&]( x) -> {
(x == ) {
(((digit[] * digit[]) % mod) * digit[]) % mod * digit[] % mod;
} {
ans = , len = ;
tmp = x;
(tmp > ) {
ans = (ans * digit[tmp % ]) % mod;
len++;
tmp /= ;
}
( i = ; i < - len; i++) {
ans = (ans * digit[]) % mod;
}
ans;
}
};
ans = ;
( a = ; a <= c; a++) {
b = c - a;
ans = (ans + (a) * (b) % mod) % mod;
}
cout << ans << ;
}
{
ios::();
cin.();
cout.();
();
t;
cin >> t;
(t--) ();
;
}

