洛谷P6218 [USACO06NOV] Round Numbers S 题解 数位DP

题目链接:https://www.luogu.com.cn/problem/P6218

题目大意:
([l,r]) 范围内有多少数满足二进制表示中的 (0) 的数量大于等于 (1) 的数量。

解题思路:
数位DP,定义状态 (f[p][z][x]) 表示:

  • 当前在第 (p) 位;
  • (z) 对应目前是否一直是前置零(true为一直是,false为不是);
  • (x) 表示 (0) 的数量减去 (1) 的数量(因为在实现时可能存在 (x) 是负数所以实现的时候加了一个 (33) 的偏移)。

示例程序如下:

#include <bits/stdc++.h>
using namespace std;
// f[p][z][x]表示第p为,z=0个数-1个数,x
int f[33][2][66], a[33], tmp;
bool vis[33][2][66];
int dfs(int p, bool z, int x, bool limit) {
    if (p == -1) {
        return x >= 0 ? 1 : 0;
    }
    if (!limit && vis[p][z][x+33]) return f[p][z][x+33];
    int res = 0, up = limit ? a[p] : 1;
    for (int i = 0; i <= up; i ++) {
        tmp += (1<<p) * i;
        bool zz = z && i==0 && p;
        int xx = x;
        if (i == 1) xx --;
        else if (!zz) xx ++;
        res += dfs(p-1, zz, xx, limit && i==up);
        tmp -= (1<<p) * i;
    }
    if (!limit) {
        vis[p][z][x+33] = true;
        f[p][z][x+33] = res;
    }
    return res;
}
int handle(int num) {
    int p = 0;
    while (num) {
        a[p++] = num % 2;
        num /= 2;
    }
    return dfs(p-1, true, 0, true);
}
int main() {
    int l, r;
    cin >> l >> r;
    cout << handle(r) - handle(l-1) << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/quanjun/p/14550130.html