转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题目:一个数转化成二进制之后,0的个数大于等于1的为round数,问一个区间内有多少round数。
http://poj.org/problem?id=3252
有点像是数位DP的题目。
转化成二进制后只有01两种情况,我们可以直接统计。
我们统计比N小的round数有多少。
对于长度比N小的数,比较简单,如果长度为L,那么高位肯定是1,然后枚举0的个数,利用组合数就能解决。
然后是长度和N一样,但是比N小的。
我们从高位开始枚举,如果出现1,则把这位看作0,那么枚举之后的低位,肯定是比原数小的。
依次下去,注意统计好高位已经出现的0,1个数。
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<vector>
#define C 240
#define TIME 10
#define inf 1<<25
#define LL long long
using namespace std;
int c[35][35];
void Init(){
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];
}
}
int slove(int n){
int len=0,bit[35];
while(n){
bit[++len]=n%2;
n/=2;
}
int sum=0;
for(int i=1;i<len;i++)
for(int j=(i+1)/2;j<i;j++)
sum+=c[i-1][j];
int one=1,zero=0;
for(int i=len-1;i;i--){
if(bit[i]){
//如果这位是1,则如果是0,枚举低位,肯定比原数小
zero++;
for(int j=max(0,(len+1)/2-zero);j<i;j++)
sum+=c[i-1][j];
//统计结束后,要恢复
zero--;
one++;
}
else
zero++;
}
return sum;
}
int main(){
int l,r;
Init();
while(cin>>l>>r)
cout<<slove(r+1)-slove(l)<<endl;
return 0;
}