【题解】codeforces441E Valera and Number

3 篇文章 0 订阅
1 篇文章 0 订阅

题目链接

题意:给定整数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),等弄懂之后再更新。。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值