A题 | A+B Problem

解题思路:

题目给出表示每个灯管点亮概率的整数pi,则每个灯管点亮概率是pi%,故障概率是(100-pi)%,这时如果要显示器显示某个合法数字,那要保证参与显示这个数字的所有灯管都点亮,而其他灯管全部故障,这时显示对应数字的概率就是需要点亮的灯管对应的概率的乘积再乘上所有故障灯管故障概率的乘积。

我用on数组存取每个灯管点亮的概率,off数组存取它们故障的概率,number数组存显示每个数字的概率,它们存的是整数,实际上第i根灯管的点亮概率是on[i]÷100,下面的几乎所有运算也像这样省略除号及之后的内容,需要作除法的操作统一留到最后处理。

根据on和off数组可以O(1)复杂度处理所有数字显示出的概率(天呐,好暴力的写法,其实写完一行就可以cv大法然后简单修改搞定剩下的)。

不要忘记取模!。

	for (int i = 1; i <= 7; i++) {
		cin >> on[i];
		off[i] = 100 - on[i];
	}
	//number[0] = on[1] * on[2] * on[3] * on[4] * on[5] * on[6] * on[7];
	number[0] = on[1] * on[2] * on[3] * off[4] * on[5] * on[6] * on[7] % mod;
	number[1] = off[1] * off[2] * on[3] * off[4] * off[5] * on[6] * off[7] % mod;
	number[2] = on[1] * off[2] * on[3] * on[4] * on[5] * off[6] * on[7] % mod;
	number[3] = on[1] * off[2] * on[3] * on[4] * off[5] * on[6] * on[7] % mod;
	number[4] = off[1] * on[2] * on[3] * on[4] * off[5] * on[6] * off[7] % mod;
	number[5] = on[1] * on[2] * off[3] * on[4] * off[5] * on[6] * on[7] % mod;
	number[6] = on[1] * on[2] * off[3] * on[4] * on[5] * on[6] * on[7] % mod;
	number[7] = on[1] * off[2] * on[3] * off[4] * off[5] * on[6] * off[7] % mod;
	number[8] = on[1] * on[2] * on[3] * on[4] * on[5] * on[6] * on[7] % mod;
	number[9] = on[1] * on[2] * on[3] * on[4] * off[5] * on[6] * on[7] % mod;

继续推导,发现四个显示器显示一个确定的四位数的概率就是其对应每个数字显示概率的乘积。

题目给的C才到2026,这时可以枚举所有可能情况,并且记录它们的概率并求和。

不要忘记取模!

	int ans = 0;
	for (int a = 0, b; a <= c; a++) {
		b = c - a;
		//a    b
		int q1, b1, s1, g1, q2, b2, s2, g2;
		q1 = a / 1000;
		b1 = a % 1000 / 100;
		s1 = a % 100 / 10;
		g1 = a % 10;

		q2 = b / 1000;
		b2 = b % 1000 / 100;
		s2 = b % 100 / 10;
		g2 = b % 10;

		int p1 = number[q1] % mod * number[b1] % mod * number[s1]  % mod * number[g1] % mod,
		    p2 = number[q2] % mod * number[b2] % mod * number[s2]  % mod * number[g2] % mod;

		ans = (ans + p1 * p2 % mod ) % mod;
	}

这时已经很接近最终答案了,但是我们还要除以一个东西,on和off数组存的数相当于是每根灯管亮或故障概率的100倍,第i根灯管点亮的概率应该是on[i]÷100,故障概率是off[i]÷100,而第i个数字点亮的概率实际是number[i]/(100^7),那对于一个四位数的显示概率要在原来的基础上÷(100^28),而我们每次枚举的是一对即两个四位数,其对应的概率要÷(100^56),这个分母大的离谱,不过是确定的,可以手算(做不到的,再写一个程序计算),算出来是549363413(分母当然也要取模了),我把它和需要取模的数一起定义在常量里了。

好了,分子分母都有了,两个一除,答案(就)就有(炸)了(了)。

题目备注了分数取模的教程,贴心的教了我们如何避免小数精度问题,我们肯定不能就这么辜负它。再来一个ksm函数求逆元,把分数取模转化成分子乘上分母逆元,结束。

int ksm(int a, int b) {
	int res = 1;
	while (b) {
		if (b & 1)
			res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}
ans = ans * ksm(fm, mod - 2) % mod;
	cout << ans << endl;

完整示例代码:

#define int long long
using namespace std;

const int mod = 998244353;
const int fm = 549363413;

int c;
int on[8], off[8]; //p[1]~p[7]  概率:p[i]/100
int number[10]; //number[0]~number[9]  概率: p p p p p p p/(100^7)

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

void solve() {
	cin >> c;
	for (int i = 1; i <= 7; i++) {
		cin >> on[i];
		off[i] = 100 - on[i];
	}
	//number[0] = on[1] * on[2] * on[3] * on[4] * on[5] * on[6] * on[7];
	number[0] = on[1] * on[2] * on[3] * off[4] * on[5] * on[6] * on[7] % mod;
	number[1] = off[1] * off[2] * on[3] * off[4] * off[5] * on[6] * off[7] % mod;
	number[2] = on[1] * off[2] * on[3] * on[4] * on[5] * off[6] * on[7] % mod;
	number[3] = on[1] * off[2] * on[3] * on[4] * off[5] * on[6] * on[7] % mod;
	number[4] = off[1] * on[2] * on[3] * on[4] * off[5] * on[6] * off[7] % mod;
	number[5] = on[1] * on[2] * off[3] * on[4] * off[5] * on[6] * on[7] % mod;
	number[6] = on[1] * on[2] * off[3] * on[4] * on[5] * on[6] * on[7] % mod;
	number[7] = on[1] * off[2] * on[3] * off[4] * off[5] * on[6] * off[7] % mod;
	number[8] = on[1] * on[2] * on[3] * on[4] * on[5] * on[6] * on[7] % mod;
	number[9] = on[1] * on[2] * on[3] * on[4] * off[5] * on[6] * on[7] % mod;

	int ans = 0;
	for (int a = 0, b; a <= c; a++) {
		b = c - a;
		//a    b
		int q1, b1, s1, g1, q2, b2, s2, g2;
		q1 = a / 1000;
		b1 = a % 1000 / 100;
		s1 = a % 100 / 10;
		g1 = a % 10;

		q2 = b / 1000;
		b2 = b % 1000 / 100;
		s2 = b % 100 / 10;
		g2 = b % 10;

		int p1 = number[q1] % mod * number[b1] % mod * number[s1]  % mod * number[g1] % mod,
		    p2 = number[q2] % mod * number[b2] % mod * number[s2]  % mod * number[g2] % mod;

		ans = (ans + p1 * p2 % mod ) % mod;
	}

	ans = ans * ksm(fm, mod - 2) % mod;
	cout << ans << endl;
}

signed main() {
	int T = 1;
	cin >> T;
	while (T--)
		solve();

	return 0;
}