ZOJ_3162 To Go or Not to Go(数论)

To Go or Not to Go

Time Limit: 1000 ms
Memory Limit: 32768 KB
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)}) ba+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+1x2i,然后处理下边界。依次考虑每一位即可。

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值