YBT高效进阶 5.3.2 区间圆数
思路
预处理 不考虑前导0
设f[i][j]表示i位中j个0
f[i][j]=f[i-1][j-1]+f[i-1][j]
f[i][0]=1
特殊处理前导0
用数位DP
CODE
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int f[51][51];
bool s[51];
int digitDP(int x)
{
if(!x)return 0;
int i,j,s0=0,s1=0,tot=0,ans=0;
for(i=1;i<32&&x;++i)s[++tot]=x&1,x>>=1;
for(i=tot;i;--i)
{
if(s[i]&&i!=tot)for(j=0;j<i;j++)if(j+s0+1>=tot-j-s0-1)ans+=f[i-1][j];
if(i!=tot)for(j=0;j<i;j++)if(j>=i-j)ans+=f[i-1][j];
s0+=!s[i],s1+=s[i];
}
if(s0>=s1)++ans;
return ans;
}
int main()
{
int i,j,l,r;
scanf("%d%d",&l,&r);
for(f[0][0]=1,i=1;i<32;++i)
for(f[i][0]=1,j=1;j<=i;++j)
f[i][j]=f[i-1][j-1]+f[i-1][j];
printf("%d",digitDP(r)-digitDP(l-1));
return 0;
}