题目描述
从前有个变量$x$,它的初始值已给出。
你会依次执行$n$次操作,每次操作有$p\%$的概率令$x=x\times 2$,$(100−p)\%$的概率令$x=x+1$。
假设最后得到的值为$w$,令$d$为$w$的质因数分解中$2$的次数,求$d$的期望。
输入格式
从文件$exp.in$中读入数据。
第一行三个整数$x,n,p$,含义见题目描述。
输出格式
输出到文件$exp.out$中。
一行一个实数,表示$d$的期望。
如果你的答案与标准答案的误差不超过$10^{−6}$,则判定为正确。
样例
样例输入1:
1 1 50
样例输出1:
1.0000000000
样例输入2:
5 3 0
样例输出2:
3.0000000000
样例输入3:
5 3 25
样例输出3:
1.9218750000
数据范围与提示
对于$20\%$的数据,$n\leqslant 20$;
对于$30\%$的数据,$n\leqslant 50$;
对于$50\%$的数据,$n\leqslant 100$;
对于$100\%$的数据,$x\leqslant 10^9,n\leqslant 200,0\leqslant p\leqslant 100$。
题解
首先,质因数分解中$2$的个数即为二进制表示下末尾$0$的个数。
考虑$DP$,设$dp[i][s][j][0/1]$表示进行第$i$次操作后,当前数的二进制表示后$8$位为$s$,第九位为$0/1$,从第九位开始往前连续$j$位相同的概率。
先来解释后$8$位的原因,因为至少要$2^8+1$次操作才可以向$9$进位,而操作数只有$200$,所以不会对答案造成贡献。
再来解释$j$的用途,假如后$8$位都是$1$第九位也是$1$,那么我们在进行$+1$的操作后会变成$1000……$,而$j$是为了计算出这个$1$的位置。
转移一共有$8$个,不再一一赘述,具体可以看代码。
时间复杂度:$\Theta(2^8n^2)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h> using namespace std; int X,N,P,mx; double gl1,gl2; double dp[201][257][300][2]; double ans; void pre_work() { int flag=X>>8,sum=0; for(int i=flag&1;(flag&1)==i&&flag;sum++)flag>>=1; if(!sum)sum++;mx=N+sum; dp[0][X&255][sum][(X>>8)&1]=1; } int judge(int x) { int res=0; while(!(x&1)){res++;x>>=1;} return res; } int main() { scanf("%d%d%d",&X,&N,&P); gl1=(double)P/100; gl2=(double)(100-P)/100; pre_work(); for(int i=0;i<N;i++) for(int s=0;s<256;s++) for(int j=1;j<=mx;j++) { if(!(((s<<1)&256)>>8))dp[i+1][(s<<1)&255][j+1][0]=dp[i+1][(s<<1)&255][j+1][0]+dp[i][s][j][0]*gl1; else dp[i+1][(s<<1)&255][1][1]=dp[i+1][(s<<1)&255][1][1]+dp[i][s][j][0]*gl1; if(((s<<1)&256)>>8)dp[i+1][(s<<1)&255][j+1][1]=dp[i+1][(s<<1)&255][j+1][1]+dp[i][s][j][1]*gl1; else dp[i+1][(s<<1)&255][1][0]=dp[i+1][(s<<1)&255][1][0]+dp[i][s][j][1]*gl1; if(s==255)dp[i+1][0][1][1]=dp[i+1][0][1][1]+dp[i][255][j][0]*gl2; else dp[i+1][s+1][j][0]=dp[i+1][s+1][j][0]+dp[i][s][j][0]*gl2; if(s==255)dp[i+1][0][j][0]=dp[i+1][0][j][0]+dp[i][255][j][1]*gl2; else dp[i+1][s+1][j][1]=dp[i+1][s+1][j][1]+dp[i][s][j][1]*gl2; } for(int s=1;s<256;s++) for(int j=1;j<=mx;j++) ans+=(dp[N][s][j][0]+dp[N][s][j][1])*judge(s); for(int j=1;j<=mx;j++)ans+=dp[N][0][j][0]*(j+8)+dp[N][0][j][1]*8; printf("%.6lf",ans); return 0; }
rp++
原文地址:https://www.cnblogs.com/wzc521/p/11670746.html