POJ 3252 Round Numbers

题意:定义一种数,满足条件:二进制表示中0个数大于等于1的个数。求给定闭区间内有多少个这种数。


思路:数位DP,dp[pos][zero][one] 表示已知二进制中首位1在第one位上,目前有零个数zero,现在要考虑pos位置上放0或1的满足条件的数的个数。记忆化搜一下就好了。


代码:

/*
    First数位DP POJ 3252
*/
#include<string.h>
#include<stdio.h>

int dp[33][33][33];
char buf[33];

int dfs(int zero,int one,int pos,int flag)
{
	int ans=0;
	if(zero!=-1 && !flag && dp[pos][zero][one]!=-1)
		return dp[pos][zero][one];
	if(pos==0)
		return one-zero<=zero;
    int end=flag?buf[pos-1]:1;
	for(int i=0;i<=end;i++){
		if(i==1 && !one)
			ans+=dfs(pos-1,pos,pos-1,flag && i==end);
		else 
			ans+=dfs(zero-i,one,pos-1,flag && i==end);
	}
	if(one && !flag){
		dp[pos][zero][one]=ans;
	}
	return ans;
}

inline int change(int x,char buf[],int r)
{
	int i=0;
	while(x){
		buf[i++]=x%2;
		x/=2;
	}
	return i;
}

inline int f(int x)
{
	int one=0,zero=0,n;
	if(x==0) return 0;
	n=change(x,buf,2);
	return dfs(-1,0,n,1);
}

int main()
{	
	int l,r;
	memset(dp,-1,sizeof(dp));
	while(~scanf("%d %d",&l,&r)){
		printf("%d\n",f(r)-f(l-1));
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值