组合数学这玩意真的是一点都粗心不得啊。
首先,这个东西是有 “可减性” 的,求区间的值,我们只要记录一下前缀和就可以了。
然后,组合数是可以DP的。
这个题,我本来是要用数位dp来搞的,但是怎么搞都搞不对,最后所有变量的意义啊,从0开始还是从1开始啊,把我搞的晕头晕脑。
算了,还是用组合数学吧。
先枚举位数比这个数小的。
对于相同位数的。
可以从高位开始枚举,如果遇到1,就这样构造:把这位变成0,剩下的位置随便放置,记录下已经有的n0和n1,让n0的大小大于等于 (len+1)/2 就可以了。
二分的问题,整体来考虑。比如这个 n0 和 n1.
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define MAX 500
#define INF 0x3f3f3f3f
#define MS(x) memset(x,0,sizeof(x))
#define ll long long
ll C[100][100];
ll solve(ll n)
{
ll ret=0;
int cnt=0;
int bit[100];
MS(bit);
while(n)
bit[++cnt]=n%2,n/=2;
for(int i=0;i<cnt;i++)
for(int j=(i+1)/2;j<i;j++)
ret+=C[i-1][j];
int n0=0,n1=0;
for(int i=cnt-1;i>0;i--)
{
if(bit[i])
{
for(int j=i-1;j+1>=(cnt+1)/2-n0&&j>=0;j--)
ret+=C[i-1][j];
n1++;
}
else
n0++;
}
return ret;
}
int main()
{
for(int i=0;i<33;i++)
{
C[i][0]=C[i][i]=1;
for(int j=1;j<i;j++)
C[i][j]=C[i-1][j]+C[i-1][j-1];
}
ll l,r;
while(cin>>l>>r)
{
cout<<solve(r+1)-solve(l)<<endl;
}
}