题意:
问区间[x,y]中有多少数的二进制表示是ABAB..AB型或者A型的,其中A是n个1,B是m个0,n,m>0
思路:
对于这个题的话 我们知道满足条件的且在(x,y)的,那么其二进制位数肯定也在x和y所对应的二进制位数之间;
所以在这里我们可以先求出x,y所对应的二进制位数,然后在这个位数区间内枚举所有满足情况的解,当然也有一些是大于y的 我们要去掉.
1.比赛的时候思路是很明确的,就是在怎么去枚举ABABAB..型的解时卡住了,当时忘了可以直接用string函数去模拟构造出来的...
2.飞巨也给我讲了一种方法,就是说可以先存储1-63位全为1的数在数组中,然后也是每次枚举A中1的个数和B中0的个数,然后进行位运算去构造出可行解....
a[i]=a[i-1]<<1|1 具体见代码...
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int manx=1e6+10;
ll a,b;
int cnt1=0,cnt2=0;
ll v=0;
set<ll>st;
ll x,y;
ll cal(string s)
{
ll ans=0;
for(int i=0;i<s.size();i++)
{
ans=ans*2+(s[i]-'0');
}
return ans;
}
void solve(int a,int b)
{
string s;//用string去模拟有几个1和0 构造
while(s.size()<=63)
{
for(int i=1;i<=a;i++)
s+="1";
if(s.size()>63)
break;
st.insert(cal(s));
for(int j=1;j<=b;j++)
s+="0";
if(s.size()>63)
break;
st.insert(cal(s));
}
return ;
}
void init()
{
st.clear();
while(a)
{
cnt1++;
a/=2;
}
while(b)
{
cnt2++;
b/=2;
}
//cout<<cnt1<<' '<<cnt2<<endl;
ll sum=0;
for(int len=cnt1;len<=cnt2;len++)
{
for(int i=1;i<=len;i++)
{
for(int j=0;j<=len-i;j++)
{
solve(i,j);
}
}
}
set<ll>::iterator it;
for(it=st.begin();it!=st.end();it++)
{
if(*it>=x&&*it<=y)
{
v++;
}
}
cout<<v<<endl;
}
int main()
{
scanf("%lld %lld",&a,&b);
x=a;
y=b;
v=0;
init();
return 0;
}
#include<bits/stdc++.h>
#define PT printf
#define SC scanf
using namespace std;
const int maxn=1e6+10;
typedef long long ll;
ll a[66];
void init()
{
a[1]=1;
for(int i=2;i<=63;i++)
a[i]=a[i-1]<<1|1;//把全为1的打出来
}
int solve(int i,int j,ll m)
{
int ans=0;
int p=i+j;
ll sum=a[i]<<j;
if(p<=63)
{
while(sum<=m)
{
ans++;
p+=i;
sum<<=i;
if(p>63)//超ll会爆
break;
sum+=a[i];
if(sum>m)
break;
ans++;
sum<<=j;
p+=j;
if(p>63)
break;
}
}
return ans;
}
int rr(ll x)
{
ll cnt=0;
if(x<=0)
return 0;
for(int i=1;i<=63;i++)
{
if(x<a[i]) break;//大于之后就没必要找了
else cnt++;
for(int j=1;j<=63-i;j++)
{
int w=solve(i,j,x);
cnt+=w;
}
}
return cnt;
}
int main()
{
ll x,y;
init();
scanf("%lld %lld",&x,&y);
printf("%d\n",rr(y)-rr(x-1));
//cout<<rr(y);
//cout<<endl<<rr(x-1);
return 0;
}