1. 程式人生 > >[CodeForces-441E]Valera and Number

[CodeForces-441E]Valera and Number

位數 nbsp reg inline val class ctype amp and

題目大意:
  給你一個數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 }

[CodeForces-441E]Valera and Number