POJ 3252-Round Numbers【二进制数位DP】

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_41785863/article/details/101998762

题意:问你一个区间内有多少个二进制下0的个数比1的多的数。

思路:dp[i][j][k] 表示第i位二进制长度为k,其中0的个数为j的答案,然后剩下的就是一些细节问题,比如计算当前总位数不能计算前导0,而且计算0的个数的时候也不能算上前导0,二进制的和十进制的相差也不大,就是在二进制上枚举而已。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
#define mid ((l + r) >> 1)
const int maxn = 1e5 + 10;
const ll inf = 0x3f3f3f3f;
ll dp[32][32][32];
int a[32];

ll dfs(int pos, int num, int cnt, int lead, int limit)
{
    if(pos == 0)
    {
        if(num && cnt && num * 2 >= cnt)
        {
            //printf("----------%d %d %d\n", pos, num, cnt);
            return 1;
        }
        return 0;
    }
    if(!limit && !lead && dp[pos][num][cnt] != -1)
        return dp[pos][num][cnt];
    int up = limit ? a[pos] : 1;
    ll ret = 0;
    for(int i = 0; i <= up; ++i)
    {   //前导0不能计算上
        ret += dfs(pos - 1, num + (i == 0 && !lead), cnt + (!lead || i), lead && (i == 0), limit && (i == up));
    }
    if(!limit && !lead) dp[pos][num][cnt] = ret;
    return ret;
}
ll slove(ll x)
{
    int tot = 0;
    while(x)
    {
        a[++tot] = x & 1;
        x >>= 1;
    }
    memset(dp, -1, sizeof(dp));
    return dfs(tot, 0, 0, 1, 1);
}

int main()
{
    ll l, r;
    scanf("%lld%lld", &l, &r);
    printf("%lld\n", slove(r) - slove(l - 1));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41785863/article/details/101998762