Luogu P1291 百事世界杯之旅

题目大意

(n) 个明星,每个明星有 (dfrac 1 n) 的概率被抽中,求充中 (n) 个明星的期望次数。

题解

(E(i)) 为抽到 (i) 个明星的期望次数,则 (E(i) = E(i-1) + sumlimits_{k=1}^{infty}k imes left(dfrac{i-1}{n} ight)^{k-1} imes dfrac{n-i+1}{n})
显然 (dfrac{i-1}{n} imes E(i) = dfrac{i-1}{n} imes E(i-1) + sumlimits_{k=1}^{infty}k imes left(dfrac{i-1}{n} ight)^k imes dfrac{n-i+1}{n})
两式相减得到

[egin{aligned}E(i) &= E(i-1) + sumlimits_{k=1}^{infty}left(dfrac{i-1}{n} ight)^{k-1} \ &= E(i-1) + limlimits_{k o infty} 1 imes dfrac{1 - left( frac{i-1}{n} ight)^k}{1 - frac{i-1}{n}} \ &= E(i-1) + dfrac{n}{n-i+1}end{aligned} ]

(E(n) = sumlimits_{i=1}^{n}dfrac{n}{i})

#include <cstdio>

long long gcd(long long a, long long b) {
	long long c;
	while (b) {
		c = a % b;
		a = b;
		b = c;
	}
	return a;
}

int n;
struct Frac {
	long long a, b;
	
	Frac(long long _a = 0, long long _b = 1) {
		a = _a;
		b = _b;
	}
	
	Frac operator + (Frac x) {
		Frac res;
		res.a = a * x.b + b * x.a;
		res.b = b * x.b;
		if (res.a) {
			long long g = gcd(res.a, res.b);
			res.a /= g;
			res.b /= g;
		} else {
			res.b = 1;
		}
		return res;	
	}
} E;

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i)
		E = E + (Frac){n, i};
	if (E.b == 1) {
		printf("%lld", E.a);
		return 0;
	}
	long long m = E.a / E.b, t1 = m, t2 = E.b, c1 = 0, c2 = 0;
	E.a %= E.b;
	while (t1) {
		++c1;
		t1 /= 10;
	}
	while (t2) {
		++c2;
		t2 /= 10;
	}
	for (int i = 1; i <= c1; ++i)
		putchar(' ');
	printf("%lld
%lld", E.a, m);
	for (int i = 1; i <= c2; ++i)
		putchar('-');
	putchar('
');
	for (int i = 1; i <= c1; ++i)
		putchar(' ');
	printf("%lld", E.b);
	return 0;
}

另一种做法:
考虑逆推,设 (E(i) = E(i+1) imes dfrac{n-i}{n} + E(i) imes dfrac{i}{n} + 1 Longrightarrow E(i) = E(i+1) + dfrac{n}{n-i})
考虑顺推,设 (E(i) = E(i-1) imes dfrac{n-i+1}{n} + E(i) imes dfrac{i}{n} + 1 Longrightarrow E(i) = E(i-1) + dfrac{n-i+1}{n-i})
显然顺推是错的,逆推是对的。
期望题逆推可能比顺推更简单
顺推做法可以参考这里

原文地址:https://www.cnblogs.com/kcn999/p/13708162.html