POJ 3252 Round Numbers (组合数学/数位dp)

题目链接

POJ3252

题目大意

求给定整数区间内有多少个“round number”.
“round number”指是指二进制形式下0的个数不少于1的个数的整数。

分析

首先这是一道区间统计问题,求[a,b]之间RN个数,答案即为b+1以内RN个数减去a以内RN个数(我这里说的以内指严格小于)。
因此,问题就转化求比整数n小的RN个数,用函数Count(n)表示。(n≤ 2,000,000,000)
计算时,首先我们需要将n转化成二进制,用bin[]数组存储,长度用bin[0]存储。
然后进行分类计算:
1.若是二进制长度比dec(n)短的数,那它一定比n小,那么
sum1= bin[0]1i=1f(i) ,f(i)表示长度为i的RN个数
而f(i)= i1j=i/2+1Cji1
i-1是因为最高位一定是1,因此可以放0的个数最多为i-1,
i/2+1是若要成为RN,至少需要放0的个数
2.若是与dec(n)位数相等的数,则需保证该位数下枚举出的数要比n小,处理方法是:从高位到低位搜索过程中,遇到当前位为0,则不处理,但要用计数器zero累计当前0出现的次数,遇到当前位为1,则先把它看做为0,zero+1,那么此时当前位 后面的 所有低位任意组合都会比k小,找出这些组合中RN的个数,统计完毕后把当前位恢复为原来的1,然后zero-1,继续向低位搜索。这样计算出sum2
Count(n)=sum1+sum2
最后还需解决组合数的计算问题,由于这里二进制位数最多大概在30位左右,范围比较小,因此可以借助杨辉三角预处理打表求得组合数。
组合数计算问题详见大神博文:组合数取模

代码

#include <iostream>
#include <cmath>
#define MAXN 35
using namespace std;
int c[MAXN][MAXN];
int bin[MAXN];
void Make_C()//利用杨辉三角求组合数
{
    for (int i=0;i<=MAXN;i++)
        for (int j=0;j<=i;j++)
            if (!j||i==j)
                c[i][j]=1;
            else
                c[i][j]=c[i-1][j-1]+c[i-1][j];
}
void Dec_to_Bin(int n)//将n转换成二进制
{
    bin[0]=0;
    while (n)
    {
        bin[++bin[0]]=n&1;
        n>>=1;
    }
}
int Count(int n)//计算出小于n的RN个数
{
    int sum=0,i,j,zero;
    Dec_to_Bin(n);
    /*计算二进制长度比Dec(n)的长度小的数中的RN个数*/
    for (i=1;i<bin[0]-1;i++)
        for (j=i/2+1;j<=i;j++)
            sum+=c[i][j];
    /*计算二进制长度等于Dec(n)的长度的数中的RN个数*/
    zero=0;//记录当前已出现0的个数
    for (i=bin[0]-1;i>=1;i--)//从高位向地位扫
        if (bin[i])
            for (j=(bin[0]+1)/2-(zero+1);j<=i-1;j++)
                sum+=c[i-1][j];
        else
            zero++;
    return sum;
}

int main()
{
    int a,b;
    Make_C();
    cin>>a>>b;
    cout<<Count(b+1)-Count(a)<<endl;
    return 0;
}

PS:看了大神的博客知道这题还可以用数位DP做,待续吧。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值