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);
}