http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=11975#problem/I
一道概率题。还是递推题。
用dp[pre][i][j]表示当前有i道正确的题,j道不正确的题。
用dp[now][i][j]表示下一个状态有i道正确的题,j道不正确的题。
如果当前是w同学,那么他有两种选择。
改错一道题,或者不做任何改变。
要是改错的话,他只能从对的里面选一道。如果要是不动的话那么他将会从错的题里面选择,而且选择的错的题不能是之前改过的。所以状态如下
if(i>0)
dp[now][i-1][j+1]+=dp[pre][i][j]*i/(n-stepw);
dp[now][i][j]+=dp[pre][i][j]*(j-stepw)/(n-stepw);
}
同理k同学的道理是一样的
if(j>0)
dp[now][i+1][j-1]+=dp[pre][i][j]*j/(n-stepk);
dp[now][i][j]+=dp[pre][i][j]*(i-stepk)/(n-stepk);
如果之前k同学或者w同学已经连续改了n题,那么要跳出,没题目让他改了。跳出后,因为下个状态还没有算出。这时没有下一个状态和上一个状态没有任何改变,所以直接复制
(尼玛我们memcpy写成memcmp,结果wa的要死。。。)
用的是滚动数组。
pre和now是两把指针。
#include<iostream> #include<stdio.h> #include<string.h> #include<string> #include<algorithm> using namespace std; double dp[2][20][20]; int pre,now; int n; double solve() { //cout<<"^^^^"<<endl; pre=0; now=1; //dp[pre][n][0]=1; char who[20]; int stepw=0; int stepk=0; int i,j; memset(dp,0,sizeof(dp)); dp[pre][n][0]=1; while(cin>>who) { //cout<<who<<"@@@@"<<endl; if(who[0]=='E')break; else for( i=0;i<=n;i++) { j=n-i; if(who[0]=='W') { if(stepw>=n)break; if(i>0) dp[now][i-1][j+1]+=dp[pre][i][j]*i/(n-stepw);//还有正确的题目就该,从正确的里面选 dp[now][i][j]+=dp[pre][i][j]*(j-stepw)/(n-stepw);//不动,从错误的里面选。不能选之前的 } else if(who[0]=='K') { if(stepk>=n)break; if(j>0) dp[now][i+1][j-1]+=dp[pre][i][j]*j/(n-stepk);//还有错误的题目就该,从正确的里面选 dp[now][i][j]+=dp[pre][i][j]*(i-stepk)/(n-stepk);//不动,从正确的里面选。不能选之前的 } /* for(int l=0;l<2;l++) { for(int k=0;k<=n;k++) { for(int o=0;o<=n;o++) cout<<dp[l][k][o]<<" "; cout<<endl; } cout<<endl; }*/ } if(i!=n+1) memcpy(dp[now],dp[pre],sizeof(dp[0]));//是memcpy啊不是memcmp if(who[0]=='W') stepw++,stepk=0; else if(who[0]=='K') stepk++,stepw=0; swap(pre,now);//交换指针 memset(dp[now],0,sizeof(dp[now])); } return dp[pre][n][0]; } int main() { while(cin>>n) { getchar(); printf("%.2lf\n",solve()); } return 0; }