Algorithm 计算斐波那契数制中设置的位?

Algorithm 计算斐波那契数制中设置的位?,algorithm,math,numbers,fibonacci,Algorithm,Math,Numbers,Fibonacci,我们知道,每个非负十进制数都可以用斐波那契数之和唯一地表示(这里我们关注的是最小表示,即,在表示一个数时,没有连续的斐波那契数,并且每个斐波那契数在表示中最多取一个) 例如: 1-> 1 2-> 10 3->100 4->101, here f1=1 , f2=2 and f(n)=f(n-1)+f(n-2); 因此,在斐波那契系统中,每个十进制数都可以表示为二进制序列。如果我们在斐波那契系统中连续写出所有自然数,我们将得到这样的序列:110100101…这称为“自然

我们知道,每个非负十进制数都可以用斐波那契数之和唯一地表示(这里我们关注的是最小表示,即,在表示一个数时,没有连续的斐波那契数,并且每个斐波那契数在表示中最多取一个)

例如:

1->  1
2-> 10
3->100
4->101, here f1=1 , f2=2 and f(n)=f(n-1)+f(n-2);
因此,在斐波那契系统中,每个十进制数都可以表示为二进制序列。如果我们在斐波那契系统中连续写出所有自然数,我们将得到这样的序列:110100101…这称为“自然数的斐波那契位序列”

我的任务是计算第1位在序列的前N位中出现的次数。因为N可以取值为1到10^15,所以我可以在不存储斐波那契序列的情况下执行此操作吗

例如:如果N是5,答案是3。

这里是O((logn)^3)

让我们计算前N位中适合的数字数量 假设我们有一个函数:

long long number_of_all_bits_in_sequence(long long M); 
它计算由不大于M的所有数字创建的“自然数斐波那契位序列”的长度

使用此函数,我们可以使用二进制搜索来查找前N位中适合的数字数量

表示前M个数字的1是多少位 让我们创建一个函数来计算有多少个数字
  • 计算m,表示序列第(N+1)位的数字。计算m对计数的贡献

  • 我们将问题简化为计算[1,m]范围内的一位数。按照的方式,将该范围划分为O(logn)个子范围,每个子范围都有一个关联的glob,如10100??,与属于该范围的数字的表示形式完全匹配。很容易计算前缀的贡献

  • 我们将问题简化为计算长度为k的所有Fibonacci字(即globs的???部分)中一位的总数T(k)。T(k)由以下循环给出

    T(0) = 0
    T(1) = 1
    T(k) = T(k - 1) + T(k - 2) + F(k - 2)
    

  • Mathematica说有一个封闭形式的解决方案,但它看起来很糟糕,而且对于这个polylog(N)来说不需要-时间算法。

    所以这只是一个算法的初步草图。当上界本身是斐波那契数时,它就起作用了,但我不确定如何将它调整为一般的上界。希望有人能改进这一点

    public static int[] fibonacciBitSequenceOfNaturalNumbers(int num) {
        int[] setBits = new int[num + 1];
        setBits[0] = 0;//anchor case of fib seq
        setBits[1] = 1;//anchor case of fib seq
        int a = 1, b = 1;//anchor case of fib seq
        for (int i = 2; i <= num; i++) {
            int c = b;
            while (c < i) {
                c = a + b;
                a = b;
                b = c;
            }//fib
            if (c == i) {
                setBits[i] = 1;
                continue;
            }
            c = a;
            int tmp = c;//to optimize further, make tmp the fib before a
            while (c + tmp != i) {
                tmp--;
            }
            setBits[i] = 1 + setBits[tmp];
        }//done
    
        return setBits;
    }
    
    总体思路是查看斐波那契编码的结构。以下是前几个数字:

         0
         1
        10
       100
       101
      1000
      1001
      1010
     10000
     10001
     10010
     10100
     10101
    100000
    
    这些数字中的不变量是,从来没有一对连续的1。给定这个不变量,我们可以使用以下模式从一个数字递增到下一个数字:

  • 如果最后一位为0,则将其设置为1
  • 如果最后一个数字是1,则由于没有任何连续的1,因此将最后一个数字设置为0,将下一个数字设置为1
  • 通过将两个数字都设置为0并将下一个数字设置为1来消除任何双1,重复此操作直到消除所有双1
  • 这一点之所以重要,是因为属性(3)告诉我们这些数字的结构。让我们再次回顾前几个斐波那契编码的数字。例如,看前三个数字:

      00
      01
      10
    
    现在,看看所有四位数字:

    1000
    1001
    1010
    
    000
    001
    010
    100
    101
    
    10000
    10001
    10010
    10100
    10101
    
    下一个数字将有五位数字,如下所示:

    1011→ 1100→ 一万

    需要注意的有趣细节是,四位数字的数量等于最多两位数字的值的数量。事实上,我们只需在最多两位数字的前面加上10就可以得到四位数字

    现在,看看三位数:

    1000
    1001
    1010
    
    000
    001
    010
    100
    101
    
    10000
    10001
    10010
    10100
    10101
    
    看看五位数:

    1000
    1001
    1010
    
    000
    001
    010
    100
    101
    
    10000
    10001
    10010
    10100
    10101
    
    请注意,五位数只是前缀为10的三位数

    这为我们提供了一个非常有趣的方法来计算有多少个1。特别是,如果你看(k+2)-数字,每一个都只是一个前缀为10的k位数字。这意味着,如果所有k位数字中都有B 1s总数,那么只有k+2位的数字中的B总数等于B加上k位数字的数量,因为我们只是在重放序列,每个数字前面加上一个额外的1

    我们可以利用这一点来计算Fibonacci编码中最多有k位数的1的数量。诀窍如下-如果我们跟踪每一位数

  • 多少个数字最多有那么多位数(称为N(d)),以及
  • 有多少个1表示最多有d位的数字(称为B(d))
  • 我们可以用这些信息来计算一个数字的这两个信息。这是一个漂亮的DP循环。最初,我们按如下方式进行种子设定。对于一个数字,N(d)=2,B(d)是1,因为对于一个数字,数字是0和1。对于两个数字,N(d)=3(只有一个两位数的数字,10,两个一位数的数字0和1)B(d)是2(1中的一个,10中的一个)。从那里,我们得到了

    • N(d+2)=N(d)+N(d+1)。这是因为最多d+2位数的数字数是最多d+1位数(N(d+1))的数字数,再加上在带有d位数(N(d))的数字前加上10所形成的数字
    • B(d+2)=B(d+1)+B(d)+N(d)(最大长度为d+2的数字中的1位总数是最大长度为d+1的数字中的1位总数,加上我们仅从d+2位数中获得的额外数字)
    例如,我们得到以下结果:

     d     N(d)      B(d)
    ---------------------
     1       2          1
     2       3          2
     3       5          5
     4       8         10
     5      13         20
    
    我们可以检查一下。对于1位数字,总共使用了1位。对于2位数字,有两个1(1和10)。对于3位数字,有5个1(1,10,100,101)。对于4位数字,有10个1(之前的5个,加上1000,1001,1010).向外扩展会得到我们想要的顺序

    这是非常容易计算的-我们可以计算
     public static void main(String... args) {
        int[] arr = fibonacciBitSequenceOfNaturalNumbers(23);
        //print result
        for(int i=1; i<arr.length; i++)
            System.out.format("%d has %d%n", i, arr[i]);
      }
    
    1 has 1
    2 has 1
    3 has 1
    4 has 2
    5 has 1
    6 has 2
    7 has 2
    8 has 1
    9 has 2
    10 has 2
    11 has 2
    12 has 3
    13 has 1
    14 has 2
    15 has 2
    16 has 2
    17 has 3
    18 has 2
    19 has 3
    20 has 3
    21 has 1
    22 has 2
    23 has 2
    
    //to return total number of set between 1 and n inclusive
    //instead of returning as in original post, replace with this code
    
                int total = 0;
                for(int i: setBits)
                    total+=i;
                return total;
    
         0
         1
        10
       100
       101
      1000
      1001
      1010 <-- we want to count ones up to here
     10000
    
    000
    001
    010
    
    dp[i] = fib[i-2] + dp[i-2] + dp[i-1];
    
         0
         1
        10
       100
       101
      1000
      1001 <-- we want to count ones up to here
      1010 
    
    0000000000