题目链接:
POJ 3252 Round Numbers
题意:
给一个区间
[a,b]
求区间中二进制表示时0的个数大于等于1的个数的数字的个数。
数据范围:
a≤b≤2∗109
分析:
数位dp。
做区间减法后,将区间上限表示成二进制形式,dfs
处理。记录下当前已有0和1的个数即可。注意剪枝。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
typedef long long ll;
int digit[35];
ll dp[35][35][35][2];
ll dfs(int pos, int zero, int one, int first, int limit)
{
if (pos == -1) return zero >= one;
if (pos + 1 + zero < one) return 0;
if (!limit && dp[pos][zero][one][first] != -1) return dp[pos][zero][one][first];
int last = limit ? digit[pos] : 1;
ll ret = 0;
for (int i = 0; i <= last; ++i) {
if (i == 0) {
int next_zero = zero + 1;
if (first) next_zero = 0;
ret += dfs(pos - 1, next_zero, one, first, limit && (i == last));
} else ret += dfs(pos - 1, zero, one + 1, 0, limit && (i == last));
}
if (!limit) dp[pos][zero][one][first] = ret;
return ret;
}
ll solve(ll x)
{
memset(dp, -1, sizeof(dp));
memset(digit, 0, sizeof(digit));
int len = 0;
while (x) {
digit[len++] = x % 2;
x /= 2;
}
return dfs(len - 1, 0, 0, 1, 1);
}
int main()
{
ll L, R;
while (~scanf("%lld%lld", &L, &R)) {
printf("%lld\n", solve(R) - solve(L - 1));
}
return 0;
}