P6218 [USACO06NOV] Round Numbers S(数位DP)

题目描述

如果一个正整数的二进制表示中,00 的数目不小于 11 的数目,那么它就被称为「圆数」。

例如,99 的二进制表示为 10011001,其中有 22 个 00 与 22 个 11。因此,99 是一个「圆数」。

请你计算,区间 [l,r][l,r] 中有多少个「圆数」。

输入格式

一行,两个整数 l,rl,r

输出格式

一行,一个整数,表示区间 [l,r][l,r] 中「圆数」的个数。

//求L到R之间圆数的个数
//圆数:0的数目不少于1的数目
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll f[100][100][100];//f(i,j)表示搜到第i位,一共有j个0,k个1的合法方案数 
int a[100],len;
ll L,R;
ll dfs (int pos,int st,int limit,int x,int y) {
	//pos表示当前位置
	//st表示前面是否全为0
	//limit表示是否有最高位限制 
	//x表示0的数量(不包含前导0)
	//y表示1的数量
	
	if (pos<=0) {
		if (st||x>=y) return 1;
		else return 0;
	} 
	if (!limit&&f[pos][x][y]!=-1) return f[pos][x][y];
	ll ans=0;
	ll k=limit?a[pos]:1;
	for (int i=0;i<=k;i++) {
		if (st&&i==0) {
			ans+=dfs(pos-1,st,limit&&i==k,x,y);
		}
		else {
			if (i==0)
				ans+=dfs(pos-1,0,limit&&i==k,x+1,y);
			else
				ans+=dfs(pos-1,0,limit&&i==k,x,y+1);
		}
	} 
	if (!limit&&!st) f[pos][x][y]=ans;
	return ans;
}
ll solve (ll x) {
	len=0;
	while (x) {
		a[++len]=x%2;
		x/=2;
	}
	memset(f,-1,sizeof(f));
	return dfs(len,1,1,0,0);
}
int main () {
	cin>>L>>R;
	cout<<solve(R)-solve(L-1);
}
posted @ 2021-03-28 22:27  zlc0405  阅读(83)  评论(0编辑  收藏  举报