1. 程式人生 > >BZOJ2227 [Zjoi2011]看電影(movie)

BZOJ2227 [Zjoi2011]看電影(movie)

只需要 sizeof mar set add post continue string script

Description

\(k\)個座位,\(n\)個人依次過來,每人隨機從\(k\)個座位中選擇一個,並從它開始不停向後走直到遇到空座位坐下。求所有人都能坐下的概率(即沒有人走到第\(k+1\)個位置)。\(n, k\leq200\),答案以有理數形式輸出。

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)) { p[i] += m; n /= i; } } } void mul(int x) { for (int i = 0, t = 0; i < len || t; ++i) { t = (A[i] = A[i] * x + t) / 10; A[i] %= 10; if (i >= len) len = i + 1; } } int main() { int T; scanf("
%d", &T); while (T--) { int n, k; scanf("%d%d", &n, &k); if (n > k) { puts("0 1"); continue; } memset(p, 0, sizeof p); add(k - n + 1, 1); add(k + 1, n - 1); add(k, -n); memset(A, 0, sizeof A); A[0] = len = 1; for (int i = 1; i <= k + 1; ++i) for (int j = 0; j < p[i]; ++j) mul(i); while (len--) printf("%d", A[len]); putchar(‘ ‘); memset(A, 0, sizeof A); A[0] = len = 1; for (int i = 1; i <= k + 1; ++i) for (int j = p[i]; j < 0; ++j) mul(i); while (len--) printf("%d", A[len]); putchar(\n); } }

BZOJ2227 [Zjoi2011]看電影(movie)