【数位DP(前导零的处理)】POJ 3252 Round Numbers

POJ 3252 Round Numbers

题意:

  • 求区间中二进制表示0的个数不小于1的个数的数的个数

思路:

  • 这个必须要考虑前导零的影响,所以设置一个布尔变量,用来记录当前位的高位是不是都是0。
  • 然后的话cnt初始值设为32(int最大数位为32位),如果高位有1,且当前位为0,那么cnt + 1;当前位为1,那么cnt - 1。跑完所有的数位之后,如果cnt >= 32就说明0的个数不小于1.
  • 记忆化的时候就必须高位有1并且无限制才可以更新dp

!!dp二维要开一维的两倍,因为我们的基点设置的是32,上下浮动有32,所以要开够。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <limits>
#include <set>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#define INF 0x3f3f3f3f

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 5e3;
int dp[35][70];
int a[35];
int s, e;

int dfs(int pos, int cnt, bool lead, bool limit)
{
    if(pos == -1)
        return cnt >= 32;
    if(!limit && !lead && dp[pos][cnt] != -1)
        return dp[pos][cnt];
    int up = limit ? a[pos] : 1;
    int ans = 0;
    for(int i = 0; i <= up; i ++ )
    {
        if(lead && i == 0)
            ans += dfs(pos - 1, cnt, lead, limit && i == a[pos]);
        else
            ans += dfs(pos - 1, cnt + (i == 0 ? 1 : -1), lead && i == 0, limit && i == a[pos]);
    }
    if(!limit && !lead)
        dp[pos][cnt] = ans;
    return ans;
}

int solve(int x)
{
    int pos = 0;
    while(x)
    {
        a[pos ++ ] = x & 1;
        x >>= 1;
    }
    return dfs(pos - 1, 32, true, true);
}
int main()
{
    memset(dp, -1, sizeof(dp));
    scanf("%d%d", &s, &e);
    printf("%d\n", solve(e) - solve(s - 1));
    return 0;
}
发布了180 篇原创文章 · 获赞 54 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/103847108