題意:給定整數x、k和概率值p,對x進行k次隨機操作,每次操作有p概率對x乘2,有1-p概率對x加1。求操作結束後,得到的數的二進制表示末尾的連續的0的數目的期望。
分析:設f[i][S][k]爲第i次操作後得到的數的二進制0~8位爲S且第8位起向後與第8位相等的數位數爲k的概率。轉移枚舉第i次狀態爲(S,k)時的操作,計算對第i+1次狀態爲(newS,newk)的貢獻即可。
代碼
#include<bits/stdc++.h>
using namespace std;
typedef double db;
const int maxS=1<<9,maxk=250,stg=8;
db f[2][maxS][maxk];
void get_0(int S,int k,int &S1,int &k1)
{
if ((S>>(stg-1)&1)==(S>>stg&1)) k++;
else k=1;
S=S*2%maxS;
S1=S;
k1=k;
}
void get_1(int S,int k,int &S1,int &k1)
{
if (S==(1<<stg)-1) k=1;
S=(S+1)%maxS;
S1=S;
k1=k;
}
int main()
{
int x,n,S0,k0=0;
db p;
cin>>x>>n>>p;p/=100;
S0=x%maxS;
if (x&(1<<stg))
{
int i=stg;
while (x&(1<<i)) k0++,i++;
}
else
{
int i=stg;
while (i<=30&&(x&(1<<i))==0) k0++,i++;
}
int pre=0,now=1;
f[now][S0][k0]=1;
for (int step=0;step<n;step++)
{
swap(pre,now);memset(f[now],0,sizeof(f[now]));
for (int S=0;S<maxS;S++)
for (int k=0;k<maxk;k++)
if (f[pre][S][k]>0)
{
int S1,k1;
get_0(S,k,S1,k1);
f[now][S1][k1]+=p*f[pre][S][k];
get_1(S,k,S1,k1);
f[now][S1][k1]+=(1-p)*f[pre][S][k];
}
}
db ans=0;
for (int S=0;S<maxS;S++)
for (int k=0;k<maxk;k++)
if (S)
{
int i=0;while ((S&(1<<i))==0) i++;
ans+=f[now][S][k]*i;
}
else ans+=f[now][S][k]*(k+stg);
printf("%.10lf",ans);
return 0;
}
似乎還有更簡單的方法(二維的dp),等弄懂之後再更新。。