http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3179
题意:举个例子来解释吧
给你两个数a b,比如 3 5
3->5的二进制数为11 100 101 110
每个数等概率出现,求1出现的概率
上述例子P=1/4*(1+1/3+2/3+2/3)
求法:先预处理一个dp[i][2] : dp[i][1]表示最高位为1,长度为i的二进制数中1的个数之和
dp[i][0]表示最高位为0,长度为i的二进制数中1的个数之和
这道题在统计的时候有一个特殊的地方,相同长度的二进制数要一起处理
然后再边界的地方仔细一点就可以了
#include<stdio.h>
#include<string.h>
double dp[30][2];
double d[30][2];
void init(){
memset(dp,0,sizeof(dp));
memset(d,0,sizeof(d));
for(int i=1;i<30;i++){
dp[i][1]=dp[i-1][1]+dp[i-1][0]+(1<<(i-1));
dp[i][0]=dp[i-1][1]+dp[i-1][0];
}
}
double CC(int num){
double sum=0;
int cnt=0;
for(int i=29;i>=0;i--){
if(num&(1<<i)){
sum+=dp[i+1][0];
sum+=(double)(1<<i)*cnt;
cnt++;
}
}
sum+=cnt;
return sum;
}
double calc(int a,int b){
double cnt=b-a+1;
double sum=0;
int f1,f2;
for(int i=29;i>=0;i--){
if(a&(1<<i)){
f1=i;
break;
}
}
for(int i=29;i>=0;i--){
if(b&(1<<i)){
f2=i;
break;
}
}
for(int i=f1+2;i<=f2;i++) sum+=dp[i][1]/i;
if(f2-f1==0){
double num=CC(b)-CC(a-1);
sum=num/(f1+1);
}
else {
int p=(1<<(f1+1))-1;
double num=CC(p)-CC(a-1);
sum+=num/(f1+1);
p=(1<<f2);
num=CC(b)-CC(p-1);
sum+=num/(f2+1);
}
return sum/cnt;
}
int main(){
int t,a,b;
init();
scanf("%d",&t);
while(t--){
scanf("%d%d",&a,&b);
printf("%lf\n",calc(a,b));
}
return 0;
}