poj2096 Collecting Bugs
传送门:http://poj.org/problem?id=2096
【题解】
看到有人在uoj群上问这个……就去看了看…
顺便复习下概率dp
$f_{i,j}$表示这个人已经找出了$i$种系统的bug,和$j$种bug的期望步数。
每次有4种转移:
1. 发现了新的bug种类,属于新的系统,那么是$f_{i+1, j+1}$,概率是$i/s * j/n$,设两者相乘为$a$;
2. 发现了新的bug种类,属于原有系统,那么是$f_{i, j+1}$,概率是$(s-i)/s * (n-j)/n$,设两者相乘为$b$;
3. 发现了原有bug种类,属于新的系统,那么是$f_{i+1, j}$,概率是$i/s * (n-j)/n$,设两者相乘为$c$;
4. 发现了原有bug种类,属于原有系统,那么是$f_{i,j}$,概率是$(n-i)/s * (n-j)/n$,设两者相乘为$d$
所以$f_{i,j} = 1 + a + b + c + d$,把$f_{i,j}$移项即可得到转移式子。
答案为$f_{0,0}$,这是经典的从后往前推概率dp。复杂度$O(ns)$。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 1e3 + 10; const int mod = 1e9+7; int n, s; ld f[M][M]; inline void prtld(const ld& x) { printf("%.4lf\n", (double)x); } // 发现了i个系统的bug,j种bug的方案数的期望 // 1. 发现了新的bug种类,属于新的系统 // 2. 发现了新的bug种类,属于原有系统 // 3. 发现了原有bug种类,属于新的系统 // 4. 发现了原有bug种类,属于原有系统 int main() { cin >> n >> s; for (int i=s; ~i; --i) for (int j=n; ~j; --j) { if(i == s && j == n) continue; f[i][j] = (f[i+1][j+1] * (s-i) * (n-j) + f[i+1][j] * (s-i) * j + f[i][j+1] * i * (n-j) + n * s) / (n * s - i * j); } prtld(f[0][0]); return 0; }