格雷码
格雷码
这道题考的有点偏,主要侧重于数学。考虑格雷码的构造方案是分成两部分,前面一部分正序,后面一部分倒序,所以可以使用二分来求解。具体的,我模拟了一下,找了找规律。
2 3
这组样例看不出什么,先分成前后两半,发现 \(3\) 在最后,所以就改成按照 10
(在前一半输出 1
,后一半输出 0
)的顺序了(先输出一个 1
),然后继续二分,发现在后一半,所以输出 0
。(这时并不能区分是每次换还是遇到不同的前后半关系再换)
3 5
如图,按照红橙绿的颜色依次二分,发现先在后半,1
,调换为 10
,然后在前一半,输出 1
,调换为 01
,然后继续后,但是还是不能区分上述括号的问题。
这时就需要再手造一组了。
这里就不写出来了。
如图所示,红橙绿蓝的顺序,最后是粉色的数,先是前 0
,再是前,又是 0
,说明如果和前一项相同的话是不改变的。继续,发现在后面一半,所以 1
,顺序变为 10
,最后还是后,所以是 0
。
根据以上的模拟过程,可以发现,初始时是前一半,顺序是 01
,每次先根据目前的顺序(第一个数是前一半,第二个数是后一半)确定输出,然后根据本次的前后半是否是上次的,如果不一样就改变顺序。
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
int n;
ll k;
bool flag=0;
int main(){
scanf("%d%llu",&n,&k);
ll l=0,r=(1ll<<n)-1;
//0 7
//0 3 4 7
while(n--){
ll mid=l+(r-l)/2;
int newflag=0;
if(k<=mid)printf("%d",flag),r=mid,newflag=0;
else printf("%d",!flag),l=mid+1,newflag=1;
if(flag!=newflag)flag=!flag;
}
return 0;
}