题目链接:
http://7xjob4.com1.z0.glb.clouddn.com/78c8eef4017b53d6dc5ecf5e0bbb6486
题目大意:
在自然数中,存在这么一些数,他们的二进制能够以ABABAB……或者ABAB……A来表示。其中A代表全部由连续的1组成的字符串,B代表全部由连续的0组成的字符串。比如73,二进制表示为1001001。现在给出区间[l,r],问在这个区间里面,有多少个符合条件的数。
范围:0~2^63。
思路:
如果以二进制来看的话,其实我们可以发现这样的数不会太多。所以我们考虑暴力。
因为我们知道了左右区间,所以我们知道了我们需要的数以二进制表示的时候长度len不会超过区间的限制。所以我们可以在len上面枚举1和0的情况,枚举出来的数保证是符合条件的但可能有一部分是超出区间范围的,然后利用位运算直接把他算出来放到set里面,最后判断一下set里面有多少个符合条件的数即可。
代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<set>
#define ll long long
using namespace std;
int main()
{
int i,j,k,t1,t2,ans;
ll x,y,a,b;
set<ll>st;
while(~(scanf("%lld%lld",&x,&y)))
{
ans=0;
st.clear();
t1=t2=0;
a=x;
b=y;
while(a){
t1++;
a=a/2;
}
while(b){
t2++;
b=b/2;
}
ll sum=0;
// printf("%d %d\n",t1,t2);
for(int len=t1;len<=t2;len++)
{
for(i=1;i<=len;i++)
{
for(j=0;j<=len-i;j++)
{
if(len%(i+j)==0){
int x=len/(i+j);
sum=0;
while(x){
for(k=1;k<=i;k++)
sum+=1<<(x*(i+j)-k);
x--;
}
st.insert(sum);
}
if((len-i)%(i+j)==0){
int x=(len-i)/(i+j);
sum=0;
while(x){
for(k=1;k<=i;k++)
sum+=1<<(x*(i+j)-k+i);
x--;
}
for(k=1;k<=i;k++)
sum+=1<<(k-1);
st.insert(sum);
}
}
}
}
set<ll>::iterator it;
for(it=st.begin();it!=st.end();it++)
{
if(*it>=x&&*it<=y){ans++;}
}
if(x==0)ans++;
printf("%d\n",ans);
}
}