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,
所以可以设一个状态:
表示当前是第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;
}