格雷码

发布时间 2023-05-22 15:40:24作者: wscqwq

格雷码

这道题考的有点偏,主要侧重于数学。考虑格雷码的构造方案是分成两部分,前面一部分正序,后面一部分倒序,所以可以使用二分来求解。具体的,我模拟了一下,找了找规律。

2 3

这组样例看不出什么,先分成前后两半,发现 \(3\) 在最后,所以就改成按照 10 (在前一半输出 1,后一半输出 0)的顺序了(先输出一个 1),然后继续二分,发现在后一半,所以输出 0。(这时并不能区分是每次换还是遇到不同的前后半关系再换)

3 5

image-20230522152430366

如图,按照红橙绿的颜色依次二分,发现先在后半,1,调换为 10,然后在前一半,输出 1,调换为 01,然后继续后,但是还是不能区分上述括号的问题。

这时就需要再手造一组了。

这里就不写出来了。

image-20230522153102076

如图所示,红橙绿蓝的顺序,最后是粉色的数,先是前 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;
}