$P5657\ [CSP-S\ 2019]$格雷码

\(AC\)并不是很难,但考试太紧张只拿了\(95pts\)
我的省选之路就从这开始吧

\(Description\)

题面
格雷码是一种编码,\(n\)位格雷码构造方式如下:
\(n-1\)位格雷码加前导\("0"\)作为\(0--2^{n-1}-1\)位,再将\(n-1\)位格雷码倒序,加前导\("1"\)作为\(2^{n-1}--2^n-1\)
特别的,\(1\)位格雷码为\(0,1\)
\(n\)位格雷码的第\(k\)个是什么

\(Solution\)

考虑写出格雷码形成了一个树形结构,找出格雷码的过程就类似数据结构查询第\(k\)位,由于\(k\)是从\(0\)开始的,所以先把他\(+1\)
假设当前考虑到第\(i\)位,则令\(mid=2^{i-1}\),假如\(k<=mid\)则补\(0\),否则\(k-=mid\),补\(1\),注意\(1\)下面的排序是倒序的,所以把排名翻转\(:k=mid-k+1\)
注意几点:
\(1.\)要开\(ull\),在\(ull\)\(x<<63\)这种运算是错的,自己写快速幂
\(2.\)极端数据\(k=2^{64}-1\)如果\(k++\)会爆\(ull\)变成\(0\),由于\(k\)在我们的程序中永远也不会变成\(0\),所以遇到\(k=0\),反转后就是\(k=1\),直接特判即可。

\(Code\)

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<string>
    #define re register
    #define ull unsigned long long
    
    using namespace std;
    
    inline ull read()
    {
        ull x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    string s;
    ull n,k,mid;
    ull quickpow(ull a,ull b)
    {
        ull ans=1;
        while(b)
        {
            if(b&1) ans=ans*a;
            a=a*a;
            b>>=1;
        }
        return ans;
    }
    int main()
    {
        n=read(),k=read();
        mid=quickpow(2,n-1);
        k++;
        while(mid)
        {
            if(k>mid||k==0) 
            {
                s+='1';
                if(!k) k=1;
                else k-=mid,k=mid-k+1;
            }
            else s+='0';
            mid>>=1;
        }
        cout<<s;
        return 0;
    }

猜你喜欢

转载自www.cnblogs.com/Liuz8848/p/12078133.html
今日推荐