BZOJ2227 [ZJOI2011] 看电影(movie)
2018 年 03 月 14 日发布.
Description
$k$个座位,$n$个人依次过来,每人随机从$k$个座位中选择一个,并从它开始不停向后走直到遇到空座位坐下。求所有人都能坐下的概率(即没有人走到第$k+1$个位置)。$n, k\leqslant200$,答案以有理数形式输出。
Solution
我们在最后一个座位之后添加第$k+1$个座位,并把这些座位连成环($k+1$后面是第$1$个)。并令所有人可以从$k+1$个座位中任选一个。
那么现在每个座位坐到人的概率都相同(因为环是对称的),为$\frac n{k+1}$。答案实际上就是第$k+1$的座位没有人的概率,即$\frac{k-n+1}{k+1}$。但是这样是在所有人都可以选$k+1$的情况下的。而如果有人选了$k+1$就一定没有算到这个概率里,所以只需要乘上$\left(\frac{k+1}k\right)^n$即可。
所以答案即为 $$ \frac{(k-n+1)(k+1)^{n-1}}{k^n} $$
有理数计算的话,质因数分解+高精即可。
Code
#include <algorithm>
#include <cstdio>
#include <cstring>
const int N = 205;
int p[N];
int A[10000], len;
void add(int n, int m) {
for (int i = 2; i <= n; ++i) if (!(n % i)) {
while (!(n % i)) {
[i] += m;
p/= i;
n }
}
}
void mul(int x) {
for (int i = 0, t = 0; i < len || t; ++i) {
= (A[i] = A[i] * x + t) / 10;
t [i] %= 10;
Aif (i >= len) len = i + 1;
}
}
int main() {
int T;
("%d", &T);
scanfwhile (T--) {
int n, k;
("%d%d", &n, &k);
scanfif (n > k) { puts("0 1"); continue; }
(p, 0, sizeof p);
memset(k - n + 1, 1);
add(k + 1, n - 1);
add(k, -n);
add(A, 0, sizeof A);
memset[0] = len = 1;
Afor (int i = 1; i <= k + 1; ++i)
for (int j = 0; j < p[i]; ++j)
(i);
mulwhile (len--) printf("%d", A[len]);
(' ');
putchar(A, 0, sizeof A);
memset[0] = len = 1;
Afor (int i = 1; i <= k + 1; ++i)
for (int j = p[i]; j < 0; ++j)
(i);
mulwhile (len--) printf("%d", A[len]);
('\n');
putchar}
}