2013 多校第五场 hdu 4649 Professor Tian

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4649

题目大意:给你n+1个数,有n个运算符,第i和i+1个数消失的概率为p[ i ],问你最后这个数的数学期望。

思路:因为只有20位,而且&,|,^都不会进位,那么一位一位地看,每一位不是0就是1,这样求出每一位是1的概率,再乘以该位的十进制数,累加,就得到了总体的期望。用d[ i ][ j ][ k ] 表示前i位前j个运算这个位为k的概率,k为0 or 1,状态转移方程:d[ i ][ j ][ k op t ] += SIMGA (d[ i ][ j ][ k ] * (1 - p[ j ])),这为没有消失,t为第j个数第i位的值,d[ i ][ j ][ k ] += SIMGA (d[ i ][ j ][ k ] * p[ j ]),这个是消失。数组可以用滚动数组。

上面是题解上的解法,比赛时我自己做的是用直接用 d[ i ][ s ] 表示前i个运算,值为s的概率,这样时间复杂度是O(n*(1<<20)),而上面的解法时间复杂度是O(20*n),快了好多啊,看来以后碰到位运算什么的题,先考虑一位一位按位来做。。 = =

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int a[222];
int op[222];

double p[222];
double d[201][2];

char str[11] ;

int main()
{
    int ca = 0 ;
    int n;
    while(~scanf("%d",&n))
    {
        for(int i = 0;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i = 1;i<=n;i++)
        {
            scanf("%s",str);
            if(str[0]=='&')
                op[i] = 0;
            else if(str[0]=='|')
                op[i] = 1;
            else op[i] = 2;
        }
        for(int i = 1;i<=n;i++)
            scanf("%lf",&p[i]);
        double ans = 0;
        for(int i = 0;i<20;i++)
        {
            for(int j = 0;j<=n;j++)
                d[j][0] = d[j][1] = 0;
            d[0][(a[0]>>i)&1] = 1;
            for(int j = 0;j<n;j++)
            {
                int t = ((a[j+1]>>i)&1);
                if(op[j+1]==0)
                {
                    for(int s = 0;s<=1;s++)
                    {
                        d[j+1][s&t] += d[j][s]*(1-p[j+1]);
                        d[j+1][s] += d[j][s]*p[j+1];
                    }
                }
                else if(op[j+1]==1)
                {
                    for(int s = 0;s<=1;s++)
                    {
                        d[j+1][s|t] += d[j][s]*(1-p[j+1]);
                        d[j+1][s] += d[j][s]*p[j+1];
                    }
                }
                else
                {
                    for(int s = 0;s<=1;s++)
                    {
                        d[j+1][s^t] += d[j][s]*(1-p[j+1]);
                        d[j+1][s] += d[j][s]*p[j+1];
                    }
                }
            }
            //printf("i = %d,d = %f,%f\n",i,d[n][1],d[n][0]);
            ans += d[n][1]*(1<<i);
        }
        printf("Case %d:\n%.6f\n",++ca,ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值