【POJ】2151 Check the difficulty of problems
http://poj.org/problem?id=2151
题意:T个队伍M条题目,给出每个队伍i的每题能ac的概率p[i][j],求所有队伍至少A掉1题且冠军至少A掉N题的概率(T<=1000, M<=30)
#include <cstdio> #include <cstring> using namespace std; const int T=1005, M=35; double d[T][M], p[T][M]; int n, m, N; void clr() { for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) d[i][j]=0; } int main() { while(scanf("%d%d%d", &m, &n, &N), !(m==0&&n==0&&N==0)) { for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) scanf("%lf", &p[i][j]); for(int i=1; i<=n; ++i) d[i][0]=1; for(int i=1; i<=n; ++i) for(int k=1; k<=m; d[i][0]*=1-p[i][k], ++k) for(int j=m; j; --j) d[i][j]=d[i][j]*(1-p[i][k])+d[i][j-1]*p[i][k]; //for(int i=1; i<=n; ++i) { for(int j=0; j<=m; ++j) printf("%.2f ", d[i][j]); puts(""); } for(int i=1; i<=n; ++i) for(int j=m; j; --j) d[i][j]+=d[i][j+1]; double ans=0, sum; for(int i=1; i<=n; ++i) { sum=d[i][N]; for(int j=1; j<i; ++j) sum*=(d[j][1]-d[j][N]); for(int j=i+1; j<=n; ++j) sum*=d[j][1]; ans+=sum; } printf("%.3f\n", ans); clr(); } return 0; }
我们只需要设状态就行了= =随便搞...
设f[i][j][k]表示第i队解决j~k个问题的概率
$$ans=\sum_{i} \left( f[i][N][M] * \prod_{j<i} f[j][1][N-1] * \prod_{j>i} f[j][1][M] \right) $$
这样就能不重不漏....(不难理解,我觉得这个很简单的吧= =
然后我们来一发前缀和,d[i][j]表示第i队解决至少j个问题的概率
$$ans=\sum_{i} \left( d[i][N] * \prod_{j<i} ( d[j][1]-d[j][N] ) * \prod_{j>i} d[j][1] \right) $$
问题转化为如何求d[i][j]...
设d'[i][j]表示第i队解决j个问题的概率
我们类似背包依次加入每个问题,有
d[i][j]=d[i][j]*(1-p[i][k])+d[i][j-1]*p[i][k](自己好好思考= =,我拐了好多个弯才想出来QAQ
于是就ok了。。。
博客地址:www.cnblogs.com/iwtwiioi 本文为博主原创文章,未经博主允许不得转载。一经发现,必将追究法律责任。