您的位置:首页 > 其它

poj 3252 数位dp(Round Number)

2015-09-07 16:40 399 查看
题意:输入两个十进制正整数a和b,求闭区间 [a ,b] 内有多少个Round number。所谓的Round Number就是把一个十进制数转换为一个无符号二进制数,若该二进制数中0的个数大于等于1的个数,则它就是一个Round Number。

思路:用dp来做:dp[i][j]表示二进制长度为 i 的数字含 j 个0的个数,比如dp[3][1] = 2(101和110)。做法就是先打表求出dp数组。然后求出a和b各有多少位,之后特判两边,中间直接求。拿样例来说:问10和1100之间的个数。先求出10~11之间的个数,再求出1000~1100之间的个数,然后求出长度为3的总个数。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
using namespace std;
#define clc(s,t) memset(s,t,sizeof(s))
#define N 36
int dp

,sum
;
int a,b;
void init(){
int i,j;
dp[1][0] = 1;
clc(sum, 0);
for(i = 2;i<=31;i++){
dp[i][0] = 1;
for(j = 1;j<i;j++){
dp[i][j] = dp[i-1][j-1]+dp[i-1][j];
if(j>=(i+1)/2)
sum[i] += dp[i][j];
}
}
}
int solve(int x,int d){
int i,j,num=0,res=0;
res = sum[d];
num = (d+1)/2;
for(i = d-1;i>0;i--){
if(0 == ((1<<(i-1))&x)){
for(j = num;j<i;j++)
res -= dp[i][j];
num--;
}
}
return res;
}
int main(){
int i,j,k,res=0;
init();
scanf("%d %d",&a,&b);
for(i = 30;i>=0;i--)
if((1<<i)&a)
break;
if((a&(a-1))==0)
res +=sum[i+1];
else
res += sum[i+1]-solve(a-1,i+1);
for(j = 30;j>=0;j--)
if((1<<j)&b)
break;
for(k = i+2;k<=j;k++)
res += sum[k];
res += solve(b,j+1);
if(i == j)
res -= sum[i+1];
printf("%d\n",res);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: