[CodeForces-441E]Valera and Number
题目大意:
给你一个数x,进行k次操作:
1.有p%的概率将x翻倍;
2.有1-p%的概率将x加1。
问最后二进制下x末尾0个数的期望。
思路:
动态规划。
由于k只到200,所以每次修改只与最后8位有关。
f[i][x][y][z]表示操作次数为i时,末尾8为表示的数字为x,第9位为y,第9位及以上和第9位数字连续相同的长度。
对于两种情况分别转移,注意特判超过8位的进位。
最后计算期望的时候,可以枚举第一维为k的所有状态,然后通过状态可以直接计算出末尾0的数量,乘上概率即可。
1 #include<cstdio> 2 #include<cctype> 3 inline int getint() { 4 register char ch; 5 while(!isdigit(ch=getchar())); 6 register int x=ch^'0'; 7 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 8 return x; 9 } 10 const int K=201; 11 double f[K][256][2][230];//[処理回数][末尾8bit][9bit目の値][9bit目の値が上にいくつ連続するか] 12 int main() { 13 int x=getint(),k=getint(); 14 double p=getint()/100.0; 15 //初始状态 16 int cnt=0,tmp=x>>8; 17 while(tmp&&((tmp&1)==((x>>8)&1))) { 18 tmp>>=1; 19 cnt++; 20 } 21 f[0][x&255][(x>>8)&1][cnt]=1; 22 for(register int i=0;i<k;i++) { 23 for(register int x=0;x<=255;x++) { 24 for(register int y=0;y<2;y++) { 25 for(register int z=0;z<230;z++) { 26 /*times 2*/ 27 f[i+1][(x<<1)&255][(x>>7)&1][(((x>>7)&1)^y)?1:(z+1)]+=f[i][x][y][z]*p; 28 /*plus 1*/ 29 if(x==255) {//特殊情况:考虑最后八位存不下而进位的情况 30 if(y) {//如果第九位是1,则相当于前面那么多1都变成0 31 f[i+1][0][0][z]+=f[i][x][y][z]*(1-p); 32 } else {//如果第九位是0,则相当于把这个0变成1 33 f[i+1][0][1][1]+=f[i][x][y][z]*(1-p);//这里把9位以后的1算作多少都没关系,因为反正最后统计的是0 34 } 35 } else { 36 f[i+1][x+1][y][z]+=f[i][x][y][z]*(1-p); 37 } 38 } 39 } 40 } 41 } 42 //计算期望 43 double ans=0; 44 for(register int x=0;x<=255;x++) { 45 for(register int y=0;y<2;y++) { 46 for(register int z=0;z<230;z++) { 47 int cnt=0,tmp=x; 48 while(cnt<8&&!(tmp&1)) { 49 cnt++; 50 tmp>>=1; 51 } 52 if(!y&&cnt==8) cnt+=z; 53 ans+=f[k][x][y][z]*cnt; 54 } 55 } 56 } 57 printf("%.13f\n",ans); 58 return 0; 59 }