简单的期望(概率dp+位运算)





2的因子个数就是它在2进制中末尾0的个数
/*
f[i][s][k][0/1] i 次操作,末8位状态s,第九位及以上相同数的位数k,第九位的数字0/1
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
double f[205][(1<<8)][200+32+5][2]; // 概率
double pj,pc;
double ans;
int n,m,x,p;
int maxs;
int ss,kk,tt; // 状态
int ct(int x){
	int cnt=0;
	while(x&&(x&1)==0) ++cnt,x>>=1;
	return cnt;
}
int main(){
	freopen("exp.in","r",stdin);
	freopen("exp.out","w",stdout);
	scanf("%d%d%d",&x,&n,&p);
	pc=1.0*p/100,pj=1.0-pc;
	maxs=1<<8;
	ss=x&(maxs-1);
	tt=((x&(1<<8))>>8);
	kk=0;
	x>>=8;
	while((x&1)==tt&&x>0) x>>=1,++kk;
	if(!kk) kk=1; // ss kk tt 暂存初始状态,循环中作为下一状态
	m=kk+n; // 最多位数
	f[0][ss][kk][tt]=1;
	for(int i=0;i<n;++i){
		for(int s=0;s<maxs;++s){
			for(int k=1;k<=m;++k){
				for(int t=0;t<=1;++t){
					if(f[i][s][k][t]<=0) continue;
					ss=s+1;
					if(s+1==maxs){
						ss=0;
						tt=t^1; // 进位,即第9为取反
						if(t==1) kk=k; // 当前第9位是1,则后面连续k个相同的仍保持相同
						else kk=1;
					}
					else tt=t,kk=k; // +1 除了前8位,后面不变
					f[i+1][ss][kk][tt]+=f[i][s][k][t]*pj; // +1
					ss=s<<1;
					if(((ss>>8)&1)==t) kk=k+1,tt=t;
					else kk=1,tt=t^1;
					ss=ss&(maxs-1);
					f[i+1][ss][kk][tt]+=f[i][s][k][t]*pc;// *2
				}
			}
		}
	}
	// 2的因子个数就是它在2进制中末尾0的个数,只需统计最后面的0即可
	for(int s=1;s<maxs;++s){
		for(int k=1;k<=m;++k){
			for(int t=0;t<=1;++t){
				ans+=f[n][s][k][t]*ct(s);
			}
		}
	}
	for(int k=1;k<=m;++k) ans+=f[n][0][k][0]*(8+k)+f[n][0][k][1]*8;
	printf("%.13lf
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Lour688/p/13816080.html