Round Numbers POJ - 3252 数位dp

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=70;
int a[N];
//设f(pos,det)f(pos,det)表示处理到pos位,当前detdet是多少的答案。
//detdet是这个二进制数0的数量减去1的数量
//当然需要注意的是,11的数量可能大于00的数量导致detdet为负,所以我们加上一个35作为基值
//如果当前前导0标记为1且本位也是0,表示当前位也是前导0,pos+1继续搜索
//如果当前前导0标记为1但本位不是0,表示当前位为该次搜索的最高位
// 
int f[N][N];
int dfs(int pos,int det,bool limit,bool lead)
{
	if(pos==0)
		return det>=35;
	//						如果不是-1,说明之前更新过了
	if(!limit && !lead && f[pos][det]!=-1)
		return f[pos][det];
	//limit是指,上一位是不是和原始数字的相同
	//也就是,是不是n的一部分 
	//如果limit存在,也就是说,上一位和n的上一位相同
	//那么当前这一位最大只能是a[pos]
	//如果limit不存在,也就是上一位比n的上一位小
	//那么当前位就可以取到1 
	int up;
	if(limit)
		up=a[pos];
	else
		up=1;
	int ans=0;
	for(int i=0;i<=up;i++)
	{
		//当前位填0,而且又前导0
		if(i==0 && lead)
			//那么继续搜
			//					 如果上一位有限制,这一位和n的这一位相同,那么limit就会传递
			//				差值还是基数 
			ans+=dfs(pos-1,35,limit && (i==a[pos]),true);
		//如果当前位填1 
		else if(i)
			//				差值减1	 限制				前导0标记情空,表示当前位为该次搜索的最高位 
			ans+=dfs(pos-1,det-1,limit&&(i==a[pos]),false);
		//如果当前位填0,没有前导0
		else
			//				  差值+1  限制传递	
			ans+=dfs(pos-1,det+1,limit&&(i==a[pos]),false);
	}
	//记录,只有当没有限制的时候 而且 没有前导0的时候 才会记录 
	if(!limit && !lead)
		f[pos][det]=ans;
	return ans;
}
int solve(int x)
{
	int len=0;
	while(x)
	{
		a[++len]=x&1;
		x>>=1;
	}
	return dfs(len,35,1,1);
}
int main()
{
	memset(f,-1,sizeof f);
	int l,r;
	cin>>l>>r;
	if(l>r)
		swap(l,r);
	cout<<solve(r)-solve(l-1)<<endl;
	return 0;
}

posted @ 2020-03-15 16:23  晴屿  阅读(112)  评论(0)    收藏  举报