Algorithm 具有一定性质的第k个二进制数的求法 我们假设我们考虑长度为 2n < /代码>的二进制数, n>代码>可能是关于代码> 1000 。我们正在寻找具有以下属性的kth编号(k受10^9限制): 1的数量等于0的数量可以如下描述:#(1)=#(0) 此数字的每个前缀必须包含至少与1一样多的0。在否定句子之后,可能更容易理解它,即:没有前缀包含比0更多的1

Algorithm 具有一定性质的第k个二进制数的求法 我们假设我们考虑长度为 2n < /代码>的二进制数, n>代码>可能是关于代码> 1000 。我们正在寻找具有以下属性的kth编号(k受10^9限制): 1的数量等于0的数量可以如下描述:#(1)=#(0) 此数字的每个前缀必须包含至少与1一样多的0。在否定句子之后,可能更容易理解它,即:没有前缀包含比0更多的1,algorithm,binary,sequence,catalan,Algorithm,Binary,Sequence,Catalan,基本上就是这样。 为了说明问题,让我们举一些例子: n=2,k=2 我们必须取长度为2n的二进制数: 0000 0001 0010 0011 0100 0101 0110 0111 1000 and so on... 现在我们必须找到满足这两个要求的第二个编号。我们看到0011是第一个,而0101是第二个。 若我们改变k=3,那个么答案就不存在了,因为有一些数字具有相同数量的相反位,但对于0110,有前缀011,所以这个数字不满足第二个约束,并且所有将1作为最高有效位的数字都是相同的 到目前为

基本上就是这样。 为了说明问题,让我们举一些例子:
n=2
k=2
我们必须取长度为2n的二进制数:

0000
0001
0010
0011
0100
0101
0110
0111
1000
and so on...
现在我们必须找到满足这两个要求的第二个编号。我们看到
0011
是第一个,而
0101
是第二个。 若我们改变
k=3
,那个么答案就不存在了,因为有一些数字具有相同数量的相反位,但对于
0110
,有前缀
011
,所以这个数字不满足第二个约束,并且所有将
1
作为最高有效位的数字都是相同的

到目前为止,我是如何找到算法的?

我的第一个想法是生成所有可能的位设置,并检查它是否具有这两个属性,但是生成它们都需要
O(2^(2n))
,这不是
n=1000
的选项

此外,我意识到,对于
n=2
000111
对于
n=3
,无需检查所有小于
0011
的数字,等等。。。坦率地说,那些最高有效位的一半保持“未触及”,因为这些数字不可能满足
#(1)=#(0)
条件。使用它,我可以将
n
减少一半,但没有多大帮助。而不是2*永远,我有永远运行的算法。它仍然是
O(2^n)
复杂性,这太大了

对算法有什么想法吗

结论

这篇文章是我读了安迪·琼斯的文章后思考的结果

首先,我不会发布我使用过的代码,因为这是Andy帖子中下面文档的第6点。你所要做的就是考虑<代码> NR 作为我所说的<代码> K<代码>。解开Dyck单词算法,将帮助我们更快地找到答案。然而,它有一个瓶颈

while (k >= C(n-i,j))
考虑到
n0&&y
因此,我们只能看到:

C(x,y) = C(x,y-1) + C(x-1,y)  where y > 0 && y < x
C(x,y)=C(x,y-1)+C(x-1,y),其中y>0&&y
可能导致溢出

让我们到此为止,并提供定义。

k-flow
-它不是整数的真正溢出,而是
C(x,y)
的值大于
k
的信息

我的想法是在每次运行上述公式后检查
C(x,y)
是否大于
k
,或者任何和分量是否为
-1
。如果我们把
-1
作为标记,那么
k-flow
已经发生了。我想很明显,如果
k-flow
数与任何正数相加,它仍然是
k-flowed
,特别是2
k-flowed
数之和是
k-flowed

我们必须证明的最后一点是,不可能产生真正的溢出。只有当我们将
a+b
中的哪一个不是
k-flowed
相加时,才可能发生真正的溢出,但作为总和,它们产生了真正的溢出


当然这是不可能的,因为最大值可以描述为
a+b您描述的数字对应。的Pt 2给出了一个按字典顺序枚举它们的简单算法。如果你想做进一步的阅读,它的参考资料应该是有用的


顺便说一句(请注意,我写这篇文章时半睡着了,所以可能是错的),维基百科的文章指出,长度为
2n
的Dyck单词的数量是
n
th加泰罗尼亚数字,
C(n)
。您可能希望找到最小的
n
,使
C(n)
大于您要查找的
k
,然后从
X^n Y^n

开始枚举Dyck单词,很抱歉上次误解了这个问题,所以我编辑了它,现在我可以保证更正,您可以先测试代码,复杂性是O(n^2)
,详细答案如下


首先,我们可以把这个问题和下一个问题相等

我们正在寻找第k个最大的
编号(k受
10^9
限制),该编号具有以下属性:

  • 1的数量
    等于
    0的数量
    可以如下描述:
    #(1)=#(0)
  • 此数字的每个前缀必须至少包含[[
    1
    0
    ]一样多的内容,这意味着:没有任何前缀包含的[[
    0
    1
    ]多的内容
让我们举一个例子来解释它:让
n=3
k=4
,满足的数字量是
5
,下面的图片解释了我们在上一个问题和新问题中应该确定的内容:

|                       000111  ------>    111000                          ^
|                       001011  ------>    110100                          |
|                       001101  ------>    110010                          |
|  previous 4th number  010011  ------>    101100  new 4th largest number  |
v                       010101  ------>    101010                          |
所以在我们解决了这个新问题之后,我们只需要按位而不是


现在的主要问题是如何解决这个新问题。首先,让A作为数组,所以
A[m]{1I还没有一个完整的解决方案,但是仔细想想,我觉得你可以通过决定n个位置放置1来构建这样的字符串,从右边开始,并且有一个规则,如果你已经有那么多的1,你只能放置0。例如,如果你有?
C(x,y) = C(x,y-1) + C(x-1,y)  where y > 0 && y < x
|                       000111  ------>    111000                          ^
|                       001011  ------>    110100                          |
|                       001101  ------>    110010                          |
|  previous 4th number  010011  ------>    101100  new 4th largest number  |
v                       010101  ------>    101010                          |
   Intention: we need the number in leftest row can be compared,
              so we add a row on DP's left row, but it's not include by DP matrix
              in the row, all the number is 1.
              the number include by bracket are initialized by ourselves
              the theory of initialize just follow the mean of DP matrix

   DP matrix = (1) (0) (0) (0)                4<=DP[5][2]=5  -->  A[1]=1
               (1) (1) (0) (0)                4>DP[4][1]=3  -->  A[2]=0, k=4-3=1
               (1) (2) (0) (0)                1<=DP[3][1]=3  -->  A[3]=1
               (1) (3)  2  (0)                1<=1  -->  a[4]=1
               (1) (4)  5  (0)                no number to compare, A[5]~A[6]=0
               (1) (5)  9   5                 so the number is 101100
/*-------------------------------------------------- 
    Environment: X86 Ubuntu GCC 
    Author: Cong Yu 
    Blog: aimager.com                              
    Mail: funcemail@gmail.com                      
    Build_Date: Mon Dec 16 21:52:49 CST 2013 
    Function: 
--------------------------------------------------*/

#include <stdio.h>

int DP[2000][1000];
// kth is the result
int kth[1000];

void Oper(int n, int k){
    int i,j,h;
    // temp is the compare number
    // jishu is the 
    int temp,jishu=0;

    // initialize
    for(i=1;i<=2*n;i++)
        DP[i-1][0]=i-1;
    for(j=2;j<=n;j++)
        for(i=1;i<=2*j-1;i++)
            DP[i-1][j-1]=0;
    for(i=1;i<=2*n;i++)
        kth[i-1]=0;

    // operate DP matrix with dynamic programming
    for(j=2;j<=n;j++)
        for(i=2*j;i<=2*n;i++)
            DP[i-1][j-1]=DP[i-2][j-2]+DP[i-2][j-1];

    // the main thought
    if(k>DP[2*n-1][n-1])
        printf("nothing\n");
    else{
        i=2*n;
        j=n;
        for(;j>=1;i--,jishu++){
            if(j==1)
                temp=1;
            else
                temp=DP[i-2][j-2];

            if(k<=temp){
                kth[jishu]=1;
                j--;
            }
            else{
                kth[jishu]=0;
                if(j==1)
                    k-=1;
                else
                    k-=DP[i-2][j-2];
            }
        }
        for(i=1;i<=2*n;i++){
            kth[i-1]=1-kth[i-1];
            printf("%d",kth[i-1]);
        }
        printf("\n");
    }
}

int main(){
    int n,k;
    scanf("%d",&n);
    scanf("%d",&k);
    Oper(n,k);
    return 0;
}