http://acm.hdu.edu.cn/showproblem.php?pid=4649
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 76 Accepted Submission(s): 48
比较简单的一道DP问题,我们设dp[i][j]表示前i个数计算完之后第j位为1的概率(二进制),那最后的答案就是
dp[n][0]*2^0+dp[n][1]*2^1+dp[n][2]*2^2+......dp[n][20]*2^20.(这里的^为乘方运算)
对于dp[i][j],设第i个符号消失的概率为pi,第(i+1)个数的第j位为di,则分三种情况考虑:
1.第i个符号为&,这时若di为1,则dp[i][j]=dp[i-1][j],否则,dp[i][j]=pi*dp[i-1][j];
2.第i个符号为|,这时若di为1,则 dp[i][j]=pi*dp[i-1][j]+1-pi,否则,dp[i][j]=dp[i-1][j];
3.第i个符号位^,这时若di为1,则dp[i][j]=dp[i-1][j]*pi+(1-pi)*(1-dp[i-1][j]);,否则,dp[i][j]=dp[i-1][j];
最后统计答案即可。注意初始化,dp[0][j]=(a[0]>>j)&1(0<=j<=20)。代码如下:
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> using namespace std; double dp[210][25]; char op[210]; double pi[210]; int a[210]; int main() { //freopen("dd.txt","r",stdin); int n,i,j,T=0; while(scanf("%d",&n)!=EOF) { printf("Case %d:\n",++T); memset(dp,0,sizeof(dp)); for(i=0;i<=n;i++) scanf("%d",&a[i]); for(i=1;i<=n;i++) cin>>op[i]; for(i=1;i<=n;i++) scanf("%lf",&pi[i]); for(i=0;i<=20;i++) { dp[0][i]=(double)((a[0]>>i)&1); } for(i=1;i<=n;i++) { for(j=0;j<=20;j++) { int tmp=(1&(a[i]>>j)); if(op[i]=='&') { if(tmp) { dp[i][j]=dp[i-1][j]; } else { dp[i][j]=pi[i]*dp[i-1][j]; } } else if(op[i]=='|') { if(tmp) { dp[i][j]=pi[i]*dp[i-1][j]+1-pi[i]; } else { dp[i][j]=dp[i-1][j]; } } else if(op[i]=='^') { if(tmp) { dp[i][j]=dp[i-1][j]*pi[i]+(1-pi[i])*(1-dp[i-1][j]); } else { dp[i][j]=dp[i-1][j]; } } } } double ans=0; for(i=0;i<=20;i++) { ans+=(double)(1<<i)*dp[n][i]; } printf("%.6lf\n",ans); } return 0; }