UPC——喜爱
程序员文章站
2022-03-26 11:34:59
...
这里是引用小s最近对数字情有独钟。他又发现了一种神奇的数字。对于数x,如果它二进制表示中只有一位是0,则x就会被小s所喜爱。比如5,二进制为101,则它被小s所喜爱。
现在,小s想知道,对于一个区间[L,R],有多少数是他所喜爱的。
对于100%的数据:L,R≤1018,T≤10000
题意:求[l,r]范围内二进制只有一位是1的数的个数;
可以看出从2i 到2i+1一共有i个满足题意的数;
用a[i]代表小于2i有多少个满足题意的数,然后根据题目的所给的[l,r]找到满最小的a[l1]>=l,a[r1]>=r,以l1,r1为上下界,然后逐一剔除或这添加满足的数,
可以看到,每一个满足的数,都是从2i+1-2开始,每次递减2k(k=1.2…);
例如[5,10]可以在所给的a中找到满足的区间[8,16];先假设a[4]-a[3]所有的数都满足,然后以8-2=6为起点每次递减2k到5停止,可以找到6 ,5 满足题意加上,然后再以16-2=14为界递减,到10停止,这时候剔除了14 .13 .11,;最后结果就是a[4]-a[3]+2-3=2;
附上自己都看不懂的代码,想像某大佬一样写DP或二分,但是本蒟蒻不会啊。
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
{
ans=(ans*a);
}
a=(a*a);
b/=2;
}
return ans;
}
ll a[500];
int main()
{
a[0]=1;
ll ans;
for(ll i=1;i<=200;i++)
a[i]=a[i-1]+i-1;
ll t;
cin>>t;
ll tp;
ll l,r,l1,r1,t1,t2;
while(t--)
{
scanf("%lld %lld",&l,&r);
if(l>r) swap(l,r);
for(ll i=0;i<=200;i++)
{
tp=qpow(2,i);
if(l<=qpow(2,i))
{
l1=qpow(2,i);
t1=i;
break;
}
}
for(ll i=0;i<=200;i++)
{
if(r<=qpow(2,i))
{
r1=qpow(2,i);
t2=i;
break;
}
}
ans=a[t2]-a[t1];
ll k=0;
for(ll i=l1-2;i>=l;k++)
{
ans++;
i-=qpow(2,k);
}
k=0;
for(ll i=r1-2;i>=r;k++)
{
ans--;
i-=qpow(2,k);
}
ll flag=0,ans2;
while(r)
{
ans2=r%2;
r/=2;
if(ans2==0)
flag++;
if(flag==2)
break;
}
if(flag==1)
ans++;
cout<<ans<<endl;
}
} ``