题目链接:http://poj.org/problem?id=3252
题意是找出l到r范围中的二进制中0的个数大于等于1的有多少个。
思路就是我们将它的二进制存起来,然后这里需要判断前导零的情况,不是很难理解,以dp[pos][n0][n1]分别来存第pos位,0的个数,1的个数,然后记忆化搜索就好了。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 35
#define ll long long
using namespace std;
int a[maxn];
ll dp[maxn][maxn][maxn];
ll dfs(int pos, int n0, int n1, bool lead, bool limit){
if(pos == -1){
if(n0 >= n1) return 1;
else return 0;
}
if(!limit && !lead && dp[pos][n0][n1] != -1) return dp[pos][n0][n1];
int up = limit ? a[pos] : 1;
ll ans = 0;
for(int i=0;i<=up;i++){
if(lead && i == 0) ans += dfs(pos - 1, 0, 0, true, limit && i == up);
else{
if(i == 0) ans += dfs(pos - 1, n0 + 1, n1, false, limit && i == up);
else ans += dfs(pos - 1, n0, n1 + 1, false, limit && i == up);
}
}
if(!limit && !lead) dp[pos][n0][n1] = ans;
return ans;
}
ll solve(ll x){
int pos = 0;
while(x){
a[pos ++] = x & 1;
x >>= 1;
}
return dfs(pos - 1, 0, 0, true, true);
}
int main()
{
ll l,r;
scanf("%lld%lld",&l,&r);
memset(dp, -1, sizeof(dp));
printf("%lld\n", solve(r) - solve(l - 1));
return 0;
}