【数位DP】poj3252

也具体不知道能不能算作数学题,姑且就归做数位DP了,各种小细节卡了半天


题意是让求区间【a,b】中有多少个符合要求的数,


所谓要求就是这个数的二进制下的0的个数要大于等于1的个数;


这种区间题首先想到的是用【1,b】的合格数减去【1,a-1】的合格数,这样我们就只需要找1->小于等于某一个数的所有合乎要求的数就行了。


假设一个数的二进制位是 1011001,十进制下是89,这个数的二进制位数是7那么所有二进制位数小于7的数并且符合要求的数都可以让【1,89】这个区间的SUM(要求数的总和)+1,这个用排列组合就行

然后找7位的小于这个数的并且符合要求的数,那么只要89的任意一个二进制下的1变成零,那么这个1之后的数位无论是0还是1生成的数都要比89小,所以我们假设我们让第四个1变成0


现在的数就变成了1010xxx,然后枚举xx中的零的个数算组合就行。

最后再判断一下这个数本身是不是符合要求。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
int c(int x,int y)
{
    if (x<0||y<0) return 0;
    if (x==0||y==0) return 1;
    int tmp=1;
    for (int i=1;i<=y;i++)
        tmp=tmp*(x-i+1)/i;
    return tmp;
}
int work(int x)
{
    if (x==0) return 0;
    int tmp_ans=0,tmp=x,now_0=0,now_1=0,tmp2_x=x,test;
    int tmp_sqr=1;
    long long now=0;
    while (tmp!=0)
    {
        now++;
        tmp_sqr=tmp_sqr<<1;
        tmp/=2;
    }
    tmp_sqr=tmp_sqr>>1;
    {
        now_1=1;
        now_0=0;
        for (int j=now-1;j>0;j--)
        {
            test=x&(1<<(j-1));
            if (test>0)
            {
                now_0++;
                for (int k=((j-1)-now_0+now_1+1)/2;k<=j-1;k++)
                    tmp_ans+=c((j-1),k);
                now_0--;
                now_1++;
                continue;
            }
            now_0++;
        }
    }
    for (int i=now-1;i>=1;i--)
        for (int j=((i+1)/2);j<=(i-1);j++)
            tmp_ans+=c(i-1,j);
    now_1=0;
    now_0=0;
    while (tmp2_x!=0)
    {
        if (tmp2_x%2==1) now_1++;
        else now_0++;
        tmp2_x=tmp2_x>>1;
    }
    if (now_0>=now_1) tmp_ans++;
    return tmp_ans;
}
using namespace std;
int main()
{
    freopen("poj3252.in","r",stdin);
    freopen("poj3252.out","w",stdout);
    int l,r,ansl,ansr;
    scanf("%d%d",&l,&r);
    ansl=work(l-1);
    ansr=work(r);
    printf("%d",ansr-ansl);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值