https://vjudge.net/contest/167400#problem/H
定义一种数,当他的二进制中1的个数在s和t之间,就叫他 next数,给定一个数,已经是next数了,问你下一个next数是谁。
比赛的时候没有想出来,用暴力枚举的方法肯定超时。以为是规律题,但是找不到,后来发现就是一个模拟。
每次如果1的个数大了,就找右边第一个,1,加上他的数, 他就变成0了,
如果1的个数少了,就找第一个0,变成1,
一次改变可能不会改变,慢慢的改,因为从最右找,肯定是最小的变化,所以就可以这样了。
第一个数的范围在int,在下一个的未必就在int,所以用long long
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
/*
比赛的时候没有想到这道题。
*/
const int maxn=200000;
int main()
{ long long m;
int T;
int s,t;
int b[maxn];
while(~scanf("%d",&T))
{for(int tt=1;tt<=T;tt++){
scanf("%lld%d%d",&m,&s,&t);
m++;//相加以便确保
while(1){
long long x=m;
int ans=0;
int len=1;
int j=0;
while(x){
b[len++]=x%2;
ans+=x%2;
x/=2;
}
//if(ans>=s&&ans<=t) break;
if(ans>t){
for(int i=1;i<len;i++){
if(b[i]==1){
j=i;break;
}
}
m+=(1ll<<(j-1));
}
else if(ans<s){
for(int i=1;i<len;i++){
if(b[i]==0){
j=i;break;
}
}
m+=(1ll<<(j-1));加上他,他就变了啊。哈哈
}
else
break;
}
printf("Case #%d: ",tt);
printf("%lld\n",m);
}
}
return 0;
}