Task
转化为2进制形如ABABAB…。A,B分别代表1,0,长度各自相同的数为sheldon数,且最高位肯定是1。
求它在[ l , r ]区间内的个数。
0<=L<=R<2^63
Solution
70分枚举•十进制
暴力求L,R区间内的数是否符合这个条件。
100分终态枚举•二进制
求区间内的数可以由前缀思想来处理。
Cal( l, r )=Cal( 0, R )-Cal( 0, L-1)
枚举二进制上1,0的个数。用二进制位移来完成数的组合。
ll L,R;
int tot;
int s[100],far[100];
struct P60{
/* 20161030.8 */
inline void chg(int x){
tot=0;s[0]=0;
while(x>0){
s[tot++]=x%2;
x>>=1;
}
}
inline bool check(){
int a,b,num[2];
far[tot-1]=tot-1;
memset(num,-1,sizeof(num));
per(i,tot-2,0){
if(s[i]==s[i+1])far[i]=far[i+1];
else far[i]=i;
}
for(int i=0;i<tot;i=far[i]+1){
if(num[s[i]]==-1)num[s[i]]=far[i]-i+1;
else if(num[s[i]]!=far[i]-i+1)return 0;
}
return 1;
}
inline void solve(){
int l=L,r=R,i,j,k,ans=0;
rep(i,l,r){
chg(i);
if(check())ans++;
}
printf("%d\n",ans);
}
}P60;
struct P100{
/* 20161030.14 位移*/
ll A[70];//有i个1 的数
int num[2];
inline void init(){
int i;rep(i,1,63)A[i]=A[i-1]<<1|1;
}
inline void print(ll x){
string S="";
while(x){
S+=((x%2)^48);
x>>=1;
}
for(int i=S.size()-1;i>=0;i--)printf("%c",S[i]);puts("");
}
inline ll cal(ll R){//[0,R] 内符合的个数
if(R<=0)return 0;
int i,j,k,cur,tot;
ll x,ans=0;
rep(i,1,63){//有i个1
num[1]=i;
if(A[i]>R)break;
else{
// print(A[i]);
ans++;//没有0的情况
}
rep(j,1,63-i){//有j个0
x=A[i];
num[0]=j;
tot=i;cur=0;
while(tot+num[cur]<=63){
tot+=num[cur];
if(cur==0)x=x<<j;
else x=x<<i|A[i];
if(x<=R)ans++;
else break;
cur^=1;
}
}
}
return ans;
}
inline void solve(){
init();
printf("%lld\n",cal(R)-cal(L-1));
}
}P100;
int main(){
// freopen("sheldon2.in","r",stdin);
// freopen("ans.out","w",stdout);
rd(L);rd(R);
if(R<=100000)P60.solve();
else P100.solve();
return 0;
}