To Go or Not to Go
Problem Description
Wyest and Winsty are two lazy kids who’d rather eat some snacks in the dorm than go to the dining hall. Wyest, however, wants to be healthy occasionally, then she’d persuade Winsty to have meals together, with the reason “Vitta will love you more if you grow some muscle”. Since Wyest likes it uncertain, she comes up with a way to decide whether they should step out of their dorms at dinner time.
They randomly choose two positive integers x, y and decide whether they’re going or not by the low -th bit of x (where l is the length of x in binary representation, and define the lowest bit to be the zeroth). If the bit is an ‘1’, they get up to the dining hall, or they just continue staying in front of their computers. Now Wyest wonders what the probability of their having meals is, if they give a range to x.
Input
The first line of input is the number of test cases T, then T lines follow, each is a test case with two positive integers a and b, both not larger than 50,000,000. a is guaranteed not to be larger than b. x is randomly chosen from the interval [a,b]. No limit on y.
Output
For each case in the input, output a separate line containing the probability (accurate to 6 fractional digits) of getting an ‘1’ in the way described above and clarified below.
Sample Input
1
4 5
Sample Output
0.500000
题意
给定区间[a,b](0<a,b<=50000000),等概率从中选取一个数x,设x二进制长度为len,会从len个二进制位中随机选一位。求最后选中的是’1’的概率。
题解:
设len(x)为x的二进制长度,one(x)为x二进制下’1’的个数,那计算’1’的个数和除以长度和不就行了?结果为
1
b
−
a
+
1
∗
(
o
n
e
(
a
)
l
e
n
(
a
)
+
o
n
e
(
a
+
1
)
l
e
n
(
a
+
1
)
+
.
.
.
.
.
+
o
n
e
(
b
)
l
e
n
(
b
)
)
\frac{1}{b-a+1}*(\frac{one(a)}{len(a)}+\frac{one(a+1)}{len(a+1)}+.....+\frac{one(b)}{len(b)})
b−a+11∗(len(a)one(a)+len(a+1)one(a+1)+.....+len(b)one(b))
因为作为分母的len(x)是可能不同的,所以不能简单求和。可以将len(x)相同的数放在一起处理,然后求分子的和即可,len(x)最多有logn个不同的值,所以最多求logn次。
接下来就是快速求区间内的数,二进制位为‘1’的数量。设求小于等于x的所有数二进制位上‘1’的数量和。分别考虑每一位为1,考虑第
i
i
i(从0开始计数)位时,规律为2i个数第i位为0,2i个数第i位为1,2i个数第i位为0,2i个数第i位为1…求出有多少个2(i+1),就有多少个2i个数第i位为1,即
a
n
s
+
=
x
2
i
+
1
∗
2
i
ans += \frac{x}{2^{i+1}}* 2^i
ans+=2i+1x∗2i,然后处理下边界。依次考虑每一位即可。
#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctype.h>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-6
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 2000100;
const int mod = 1000000007;
double solve(int a, int b);
LL getone(LL x);
int main()
{
int t, a, b;
LL up, dn;
scanf("%d", &t);
while(t--)
{
scanf("%d %d", &a, &b);
printf("%.6f\n", solve(a, b));
}
return 0;
}
double solve(int a, int b)
{
int i, j, k, l, r, num = b-a+1;
double p = 0;
for(i=0;i<28;i++)
{
j = 1<<i;
l = max(a, j);
r = min(j*2-1, b);
if(l<=r)
{
LL len = i+1;
LL num = getone(r)-getone(l-1);
p += (num*1.0)/len;
}
}
return p/num;
}
//求<=x的所有数二进制位为‘1’的数量
LL getone(LL x)
{
LL sum = 0, i, j;
for(i=0;i<30;i++)
{
j = 1LL<<(i+1);
sum += (x/j) * (j/2);
if(x%j >= j/2)
sum += x%j - j/2+1;
}
return sum;
}