Round Number --数位DP

如果一个数的二进制表示里面,0的个数大于等于1 的个数(不计算前导0),那么这个叫做round number。

求一个给定区间内的round number。

思路:

假设一个二进制数的第 i 位(从右往左数,从1 开始)是1 的话,那么当第i位为0的时候,从这个数的第 i 位往右的那些二进制位可以是任何数(1或者0 ),换句话说,就是第 i 位右边的 二进制位不论是1还是0都小于原来的数字的,于是用一下组合数学就可以求解了。

假设第 i 位的左边没有出现1,那么第 i 位左边的0 就可以忽略不计,如果出现了1 ,那么第i位左边的0就要计算在内,然而,只有最后一个二进制位(从右往左)的左边没有1,所以只需要对最后一位特殊处理一下。

接下来论靠直接 debug 的重要性,由于 数字0 实在是太TM 的特殊了,我的代码里用一个函数计算所有小于n 的round number ,但是当n等于 1的时候,这个函数返回0,正确答案是1,我想这应该是一个唯一的情况,所以对1进行了特殊判断(见solve函数),于是还真就只是这么一个特殊情况。

更详细的细节参见代码

#include<iostream>
#include<cstring>
#include<cstdio>
#define bug
using namespace std;
const int MAXN = 40;
int num[MAXN],len;
int c[MAXN][MAXN];
int dp[MAXN];
//dp[i]表示长度为i的所有以1开头的所有的二进制数的round number 个数
void init_c()
{
	for(int i=0;i<MAXN;i++)c[i][0]=1;
	for(int i=1;i<MAXN;i++)
	{
		for(int j=1;j<MAXN;j++)
			c[i][j]=c[i-1][j]+c[i-1][j-1];
	}
	dp[1]=1;
	for(int i=2;i<MAXN;i++)
	{
		dp[i]=0;
		int tar = (i-1)/2+1;
		for(int j=tar;j<=i-1;j++)
		{
			dp[i] += c[i-1][j];
		}
	}
	#ifdef bug2
	for(int i=1;i<=33;i++)
		printf("dp[%d]->%d ",i,dp[i]);
	#endif
}


int solve(int n)
{
	if(n==1)return 1;
	len = 1;
	int temp  = n;
	while(n)
	{
		num[len++]=n%2;
		n/=2;
	}
	len--;
	int nOne = 1;
	int nZero=0,stdZero=0,tarZero;
	stdZero = len/2+(len&1);
	int res = 0;
	for(int i=1;i<len;i++)res+=dp[i];
	for(int i=len-1;i;i--)
	{
		if(num[i])
		{
			tarZero = stdZero - nZero - nOne;
			for(int j=tarZero;j<i;j++)
			{
				res += c[i-1][j];
			}
		}
		else
		{
			nZero++;
		}
	}
	#ifdef bug3
	printf("n=%d res=%d\n",temp,res);
	#endif
	return res;
}
int main()
{
	freopen("data.in","r",stdin);
	init_c();
	int a,b;
	while(~scanf("%d%d",&a,&b))
	{
		printf("%d\n",solve(b+1)-solve(a));
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值