[ACM] POJ 3252 Round Numbers (的范围内的二元0数大于或等于1数的数目,组合)

简介:
Round Numbers
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 8590   Accepted: 3003

Description

The cows, as you know, have no fingers or thumbs and thus are unable to play Scissors, Paper, Stone' (also known as 'Rock, Paper, Scissors', 'Ro, Sham, Bo', and a host of other names) in order to make arbitrary decisions such as who gets to be milked first. They can't even flip a coin because it's so hard to toss using hooves.

They have thus resorted to "round number" matching. The first cow picks an integer less than two billion. The second cow does the same. If the numbers are both "round numbers", the first cow wins,
otherwise the second cow wins.

A positive integer N is said to be a "round number" if the binary representation of N has as many or more zeroes than it has ones. For example, the integer 9, when written in binary form, is 1001. 1001 has two zeroes and two ones; thus, 9 is a round number. The integer 26 is 11010 in binary; since it has two zeroes and three ones, it is not a round number.

Obviously, it takes cows a while to convert numbers to binary, so the winner takes a while to determine. Bessie wants to cheat and thinks she can do that if she knows how many "round numbers" are in a given range.

Help her by writing a program that tells how many round numbers appear in the inclusive range given by the input (1 ≤ Start < Finish ≤ 2,000,000,000).

Input

Line 1: Two space-separated integers, respectively  Start and  Finish.

Output

Line 1: A single integer that is the count of round numbers in the inclusive range  Start.. Finish

Sample Input

2 12

Sample Output

6

Source


解题思路:

题意为在一个闭区间内,有多少个数它的二进制中0的个数大于等于1的个数。

整体思路为: 比方求 [2,12],  我们就求 (0,12] -(0,1]。

这样问题就转化为了 求(0,n]之间有多少个符合题意的数。

下面转载为:http://hi.baidu.com/ycdoit/item/6f64473c54a88f607d034b7f

[2,12]区间的RoundNumbers(简称RN)个数:Rn[2,12]=Rn[0,12]-Rn[0,1]
 即:Rn[start,finish]=Rn[0,finish]-Rn[0,start-1]
 所以关键是给定一个X,求出Rn[0,X]
 如今如果X=10100100 
 这个X的二进制总共是8位。不论什么一个小于8位的二进制都小于X
 第一部分,求出长度为[0,7]区间内的二进制是RoundNumber的个数
  对于一个长度为Len的二进制(最高位为1)。怎样求出他的RoundNumbers呢(如果为用R(len)来表达),分为奇数和偶数两种情况
  1、奇数情况:在Len=2k+1的情况下。最高位为1,剩下2k位。至少须要k+1为0
   用C(m,n)表示排列组合数:从m个位置选出n个位置的方法
   R(len)=C(2k,k+1)+C(2k,k+2)+...+C(2k,2k).
   因为 A:C(2k,0)+C(2k,1)+...+C(2k,2k)=2^(2k)
     B:C(2k,0)=C(2k,2k), C(2k,1)=C(2k,2k-1) ,,C(2k,i)=C(2k,2k-i)
   于是  C(2k,0)+C(2k,1)+...+C(2k,2k)
    = C(2k,0)+C(2k,1)+...+C(2k,k)+C(2k,k+1)+C(2k,K+2)+...+C(2k,2k)
    = 2*R(len)+C(2k,k)
    =2^(2k)
    所以R(len)=1/2*{2^(2k)-C(2k,k)};
  2. 偶数情况 len=2*k,类似能够推到 R(len)=1/2*(2^(2k-1));
 第二部分,对于上面这个长度为8的样例:即X=10100100,首先假设本身是RoundNumbers,第二部分的结果总数+1
  第一部分已经将长度小于8的部分求出。如今要求长度=8的RoundNumber数目
  长度为8。所以第一个1不可改变
  如今到第二个1。假设Y是前缀如100*****的二进制,这个前缀下。后面取0和1必定小于X。已经有2个0,一个1。剩下的5个数字中至少须要2个0,
   所以把第二个1改为0:能够有C(5,2)+C(5,3)+C(5,4)+C(5,5)
  如今第三个1,也就是前最为101000**,相同求出。至少须要0个0就可,所以有C(2,0)+C(2,1)+C(2,2)个RoundNumbers
  。

。。


  将所有除了第一个1以外的1所有变为0,如上算出有多少个RoundNumbers,结果相加(因为前缀不一样。所以后面无论怎么组合都是唯一的)

 将第一部分和第二部分的结果相加,就是最后的结果了。
 精度要求方面,用int就能够了:two billion=20亿<2*1024*1024*1024=2^31,需用31位来表示数组。由于第一位总是1,所以求组合数的时候最多求30,C(30,k),k取值区间是[0,30],由于C(k,i)<2^k,所以结果用int表示就能够


參考:http://www.cnblogs.com/kuangbin/archive/2012/08/22/2651730.html


代码:

#include <iostream>
#include <string.h>
using namespace std;
int c[32][32];
int b[32];

void getCom()
{
    memset(c,0,sizeof(c));
    c[0][0]=c[1][0]=c[1][1]=1;
    for(int i=2;i<=30;i++)
    {
        c[i][i]=c[i][0]=1;
        for(int j=1;j<=i;j++)
            c[i][j]=c[i-1][j]+c[i-1][j-1];
    }
}

int cal(int n)
{
    if(n<=1)//注意正整数,0不是round number
        return 0;
    int bit=0;
    int temp=n;
    int ans=0;

    while(temp)//b[]保存每一位二进制数,一共bit位
    {
        b[bit++]=temp%2;
        temp/=2;
    }

    for(int i=bit-1;i>=1;i--)//位数比当前数少一位的round number
    {
        if(i%2==0)
            ans+=(1<<(i-1))/2;
        else
            ans+=((1<<(i-1))-c[i-1][(i-1)/2])/2;
    }

    int num0=0,num1=0;
    for(int i=0;i<bit;i++)//推断自身
        if(b[i])
            num1++;
        else
            num0++;
    if(num0>=num1)
        ans++;

    num0=0;num1=1;
    for(int i=bit-2;i>=0;i--)
    {
        if(b[i]==0)
            num0++;
        else
        {
            num1++;
            for(int k=i;k>=0&&k+num0+1>=i-k+num1-1;k--)//k是选择0的个数。总共0的个数要大于等于1的个数
                ans+=c[i][k];
        }
    }
    return ans;
}

int main()
{
    getCom();
    int a,b;
    cin>>a>>b;
    cout<<cal(b)-cal(a-1)<<endl;
    return 0;
}


版权声明:本文博客原创文章,博客,未经同意,不得转载。





本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/4656892.html,如需转载请自行联系原作者


相关文章
|
8月前
|
测试技术 数据库 开发工具
云产品评测|操作系统智能助手OS Copilot新功能
我是一名测试工程师,主要负责App和Web端的测试,有时会使用阿里云服务器进行服务端问题定位及数据库等云资源的操作。在使用OS Copilot过程中遇到了一些问题: 1. **命令执行失败**:在解决Vim中文乱码时,Copilot建议的命令看似正确,但实际并未创建或修改`.vimrc`文件。 2. **任务文件解析问题**:使用`-f`功能解析任务文件时,Copilot未能正确执行获取容器日志的任务。 3. **管道功能不稳定**:管道功能对文件内容解释有效,但在某些情况下需要更明确的提示词才能正常工作。
|
网络协议 Linux
【系统DFX】如何诊断占用过多 CPU、内存、IO 等的神秘进程?
【系统DFX】如何诊断占用过多 CPU、内存、IO 等的神秘进程?
252 0
|
存储 缓存 数据挖掘
通过1688店铺所有商品API接口一键获取店铺所有商品信息
本文介绍了如何使用1688开放平台的API接口一键获取店铺所有商品信息。通过详细的分析和实例代码,我们将带领读者了解整个流程,包括API接口的调用、数据的解析和处理等方面。
|
存储 监控 安全
深入理解 Linux 文件系统:从根目录到用户主目录
深入理解 Linux 文件系统:从根目录到用户主目录
847 0
|
机器学习/深度学习 人工智能 算法
数智洞察|通义大模型如何助力产业真正智能化
数智洞察|通义大模型如何助力产业真正智能化
755 0
|
移动开发 开发框架 JavaScript
vue常用组件库
vue常用组件库
529 0
|
SQL Oracle 关系型数据库
CentOS安装MySQL 5.7 - RPM(结尾附视频)
CentOS安装MySQL 5.7 - RPM(结尾附视频)
590 0
|
消息中间件 SQL JSON
Apache Doris Routine Load数据导入使用方法
Routine Load 是支持用户提交一个常驻的导入任务,通过不断的从指定的数据源读取数据,将数据导入到 Doris 中。目前仅支持通过无认证或者 SSL 认证方式,从 Kakfa 导入的数据。
957 0
Apache Doris Routine Load数据导入使用方法
|
开发框架 运维 Kubernetes
蚂蚁宣布开源KubeTEE:云原生集群化机密计算框架
Kubernetes+TEE,为云原生补上机密计算拼图
4373 1
蚂蚁宣布开源KubeTEE:云原生集群化机密计算框架

热门文章

最新文章