JZOJ5805. 【2018.08.12提高A组模拟】 简单的期望

87 篇文章 0 订阅
11 篇文章 0 订阅

Description

从前有个变量 x,它的初始值已给出。
你会依次执行 n 次操作,每次操作有 p% 的概率令 x = x × 2,(100 − p)% 的概率令 x = x + 1。
假设最后得到的值为 w,令 d 为 w 的质因数分解中 2 的次数,求 d 的期望。

Input

从文件 exp.in 中读入数据。
第一行三个整数 x, n, p,含义见题目描述。

Output

输出到文件 exp.out 中。
一行一个实数,表示 d 的期望。
如果你的答案与标准答案的误差不超过 10−6,则判定为正确。

Sample Input

【样例 1 输入】
1 1 50
【样例 2 输入】
5 3 0
【样例 3 输入】
5 3 25

Sample Output

【样例 1 输出】
1.0000000000
【样例 2 输出】
3.0000000000
【样例 3 输出】
1.9218750000

Data Constraint

对于 20% 的数据,n ≤ 20;
对于 30% 的数据,n ≤ 50;
对于 50% 的数据,n ≤ 100;
对于 100% 的数据,x ≤ 10^9, n ≤ 200, 0 ≤ p ≤ 100。

题解

可以知道,它2的因子个数就是它在2进制中末尾0的个数。
考虑到操作次数只有200,
所以可以设一个状态:
fi,s,k,t f i , s , k , t 表示当前是第i个操作,这个数二进制中的后八位的状态为s,第9位往前连续相同数的个数,以及第9位是什么。
转移就很简单,
枚举状态,分别进行+1和*2操作,得出新的状态,
将这个状态的概率*操作的概率加到新状态里面。
统计答案也很简单。

code

#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#define ll long long
#define N 100003
#define M 103
#define db double
#define P putchar
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

int n,m,x,w;
int ss,kk,tt;
db p,q,ans,f[203][260][303][2];

int calc(int x)
{
    int s=0;
    for(;x%2==0;x>>=1)s++;
    return s;
}

int main()
{
    freopen("exp.in","r",stdin);
    freopen("exp.out","w",stdout);

    read(x);read(n);read(m);
    p=1.0*m/100;q=1-p;

    w=1<<8;
    ss=x&(w-1);
    x=x>>8;
    tt=x%2;
    kk=0;
    for(;x%2==tt && x>0;kk++)x>>=1;
    if(kk==0)kk=1;
    m=n+kk;

    f[0][ss][kk][tt]=1;

    for(int i=0;i<n;i++)
        for(int s=0;s<w;s++)
            for(int k=1;k<=m;k++)
                for(int t=0;t<2;t++)
                    if(f[i][s][k][t]>0)
                    {
                        ss=s+1;
                        if(ss==w)
                        {
                            ss=0;
                            tt=t^1;
                            if(t==1)kk=k;else kk=1;
                        }else kk=k,tt=t;
                        f[i+1][ss][kk][tt]=f[i+1][ss][kk][tt]+f[i][s][k][t]*q;

                        //+1

                        ss=s<<1;
                        if(((ss&w)>>8)==t)kk=k+1,tt=t;else kk=1,tt=t^1;
                        ss=ss&(w-1);
                        f[i+1][ss][kk][tt]=f[i+1][ss][kk][tt]+f[i][s][k][t]*p;

                        //*2

                    }

    for(int s=1;s<w;s++)
        for(int k=1;k<=m;k++)
            for(int j=0;j<2;j++)
                ans=ans+f[n][s][k][j]*calc(s);

    for(int k=1;k<=m;k++)
        ans=ans+f[n][0][k][0]*(8+k)+f[n][0][k][1]*8;

    printf("%.13lf",ans);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值