【題解】codeforces441E Valera and Number

題目鏈接

題意:給定整數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),等弄懂之後再更新。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章