poj3252.Round Numbers,组合数

曾经,离开的时候,utoppia同学和我打赌说我的POJAC题数不会超过300。
现在,我又回来,固执地做着没落的POJ,只为那个约定。你却再没有机会和我并肩作战。
不久,我们队又将出发,带着utoppia的名字,继续未完成的梦。

废话完毕。
Poj3252.Round Numbers。
将数化成二进制,问在[start,finish]区间内的数满足0的位数大于等于1的位数的数有多少个。

对于这种区间问题,显然可以变成[1,finish]-[1,start-1]来处理。
对于一个数N,[1,N]区间的满足要求的数怎么求呢。
举个例子,对于1010001这样的数,可以这样分类:

1.
1
1X
1XX
1XXX
1XXXX
1XXXXX

即长度小于N的数。

2.

1010001

就是N。

3.

1010000

100XXXX
长度等于N,从某一位(1..l-1)开始小于N的数。
XXXX..代表任意0、1串。

分成这三类后,只要在XXXX..中取得足够多的0,使得总的0数量大于1的数量即可。
通过组合数可以计算XXXX中选得足够多的0的的取法。

组合数预处理得到。分类的第一种数也可以预处理得到。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define NN 50

long long c[NN][NN];

void init(int n){
    int i,j;
    memset(c,0,sizeof(c));
    for(i=0;i<=n;++i){c[i][0]=c[i][i]=1;}

    for(i=1;i<=n;++i){
        for(j=1;j<i;++j){
            c[i][j]=c[i-1][j]+c[i-1][j-1];
        }
    }
}

int b[NN],sum0[NN];

long long work(int n){
    if (n==0) return 0;
    int l=0,i,j,lb,tmp,tl;
    long long ret=0;
    while(n){
        b[++l]=n%2;
        n=n/2;
    }
    sum0[l+1]=0;
    for(i=l;i>=1;--i){
        sum0[i]=sum0[i+1]+(b[i]==0?1:0);
    }

    for(i=1;i<l;++i){              //1
        for(j=(i+1)/2;j<=i-1;++j){
            ret+=c[i-1][j];
        }
    }

    lb=(l+1)/2;                     //2
    if (sum0[1]>=lb) ret++;         

    for(i=1;i<l;++i){               //3
        if (b[i]==1){
            tmp=sum0[i+1]+1;
            tl=i-1;
            for(j=max(lb-tmp,0);j<=tl;++j){
                ret+=c[tl][j];
            }
        }
    }
    return ret;
}

int main(){
    init(33);
    int st,ed;
    long long ans;
    while(scanf("%d%d",&st,&ed)!=EOF){
        st--;
        ans=work(ed)-work(st);
        printf("%I64d\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值