Блог пользователя kien_coi_1997

Автор kien_coi_1997, 12 лет назад, По-английски

Based on the approach in my previous blog, today, I found an amazing way to calculate large fibonacci numbers (in some modulo). According to part IV of my previous blog, let f(n) be the (n + 1)th fibonacci number, we have two case: n is even and n is odd.

  • f(2 * k) = f(k) * f(k) + f(k - 1) * f(k - 1)
  • f(2 * k + 1) = f(k) * f(k + 1) + f(k - 1) * f(k)

There are only at most states. I don't like to prove this, but I can ensure it is true by doing some following experiment. Let's divide n into groups by depth, you will realize a special property: Each depths only contains at most 4 values of n.

call f(1000):


Depth[0] : 1000 Depth[1] : 499 500 Depth[2] : 248 249 250 Depth[3] : 123 124 125 Depth[4] : 60 61 62 63 Depth[5] : 29 30 31 32 Depth[6] : 13 14 15 16 Depth[7] : 5 6 7 8 Depth[8] : 1 2 3 4 Depth[9] : 0 1 2 Depth[10] : 0 1

call f(123123123122):


Depth[0] : 123123123122 Depth[1] : 61561561560 61561561561 Depth[2] : 30780780779 30780780780 30780780781 Depth[3] : 15390390388 15390390389 15390390390 15390390391 Depth[4] : 7695195193 7695195194 7695195195 7695195196 Depth[5] : 3847597595 3847597596 3847597597 3847597598 Depth[6] : 1923798796 1923798797 1923798798 1923798799 Depth[7] : 961899397 961899398 961899399 961899400 Depth[8] : 480949697 480949698 480949699 480949700 Depth[9] : 240474847 240474848 240474849 240474850 Depth[10] : 120237422 120237423 120237424 120237425 Depth[11] : 60118710 60118711 60118712 60118713 Depth[12] : 30059354 30059355 30059356 30059357 Depth[13] : 15029676 15029677 15029678 15029679 Depth[14] : 7514837 7514838 7514839 7514840 Depth[15] : 3757417 3757418 3757419 3757420 Depth[16] : 1878707 1878708 1878709 1878710 Depth[17] : 939352 939353 939354 939355 Depth[18] : 469675 469676 469677 469678 Depth[19] : 234836 234837 234838 234839 Depth[20] : 117417 117418 117419 117420 Depth[21] : 58707 58708 58709 58710 Depth[22] : 29352 29353 29354 29355 Depth[23] : 14675 14676 14677 14678 Depth[24] : 7336 7337 7338 7339 Depth[25] : 3667 3668 3669 3670 Depth[26] : 1832 1833 1834 1835 Depth[27] : 915 916 917 918 Depth[28] : 456 457 458 459 Depth[29] : 227 228 229 230 Depth[30] : 112 113 114 115 Depth[31] : 55 56 57 58 Depth[32] : 26 27 28 29 Depth[33] : 12 13 14 15 Depth[34] : 5 6 7 8 Depth[35] : 1 2 3 4 Depth[36] : 0 1 2 Depth[37] : 0 1

According to the amazing property, we can calculate 1018-th fibonacci number by using little code:


#include <map> #include <iostream> using namespace std; #define long long long const long M = 1000000007; // modulo map<long, long> F; long f(long n) { if (F.count(n)) return F[n]; long k=n/2; if (n%2==0) { // n=2*k return F[n] = (f(k)*f(k) + f(k-1)*f(k-1)) % M; } else { // n=2*k+1 return F[n] = (f(k)*f(k+1) + f(k-1)*f(k)) % M; } } main(){ long n; F[0]=F[1]=1; while (cin >> n) cout << (n==0 ? 0 : f(n-1)) << endl; }

The complexity of above code is

You can reproduce my experiment by using this code.

  • Проголосовать: нравится
  • +118
  • Проголосовать: не нравится

»
12 лет назад, скрыть # |
 
Проголосовать: нравится +8 Проголосовать: не нравится

I did implemented this code before too. Its nice and shorter than Matrix exponentiation. I have found this on wikipedia Fibonacci Numbers.

F[2*n — 1] = F[n]*F[n] + F[n — 1]^2

F[2*n] = (F[n — 1] + F[n + 1])*F[n] = (2*F[n — 1] + F[n])*F[n]

»
12 лет назад, скрыть # |
Rev. 2  
Проголосовать: нравится -62 Проголосовать: не нравится

I have a marvellous way to calculate fibonacci number using only TWO lines of code :P

See here.

»
12 лет назад, скрыть # |
 
Проголосовать: нравится -22 Проголосовать: не нравится

Nice article. I wonder if you can you somehow invent a way to calculate k-inversions faster than ? for example.

»
12 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Although the observation is interesting, I don't get what relevance it has in the above implementation. I would write pretty much the same code without the realizing that each depth has at max 4 states. Could you please clarify?

  • »
    »
    12 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    I didn't understand you question well. My following answer can be not appropriate.

    This such small complexity is unintentional. I expected to find a solution .

    • »
      »
      »
      12 лет назад, скрыть # ^ |
       
      Проголосовать: нравится 0 Проголосовать: не нравится

      What I mean to say is at at each of the log(n) levels, there are going to be 4 possible values. But how does that effect the algorithm, what is the use of this information? I have these results: ~~~~~ f(2 * k) = f(k) * f(k) + f(k - 1) * f(k - 1) f(2 * k + 1) = f(k) * f(k + 1) + f(k - 1) * f(k) ~~~~~

      Couldn't I just use these 2 results and obtain in logarithmic time?

      Well, As I look at it, I might be getting what your point is, so basically if I have calculated f(k), I might very well have lots of required values for f(k-1), and that's what makes the algorithm faster. I suppose this is what you mean to say?

»
12 лет назад, скрыть # |
Rev. 3  
Проголосовать: нравится +56 Проголосовать: не нравится

Forgive me but this does not strike me as anything special. It is basically just a poor man's version of the matrix multiplication + exponentiation by squaring anyway (the computed values should be the same). Plus, you are losing the insights from linear algebra, so it will be harder for you to see the solution for less trivial recurrence relations.

Computing Fibonacci numbers using matrix multiplication requires approximately the same amount of code as your approach:

MOD = 1000000007
def mul(A,B):
    return [ [ sum(A[r][i]*B[i][c] for i in range(2))%MOD for c in range(2) ] for r in range(2) ]

def exp(A,n):
    if n==0: return [ [1,0], [0,1] ]
    C = exp(A,n//2)
    C = mul(C,C)
    return mul(A,C) if n%2 else C

n = int( input() )
print( exp( [ [0,1], [1,1] ], n )[0][1] )

(And finally, the line "#define long long long" is both ugly and a really bad habit.)

»
12 лет назад, скрыть # |
Rev. 2  
Проголосовать: нравится +32 Проголосовать: не нравится

cool. but can be cooler

void fib(ll n, ll&x, ll&y){
    if(n==0){
        x = 0;
        y = 1;
        return ;
    }
     
    if(n&1){
        fib(n-1, y, x);
        y=(y+x)%mod;
    }else{
        ll a, b;
        fib(n>>1, a, b);
        y = (a*a+b*b)%mod;
        x = (a*b + a*(b-a+mod))%mod;
    }
}

answer in x. no map, time — logN.

»
11 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

"Let's divide n into groups by depth, you will realize a special property: Each depths only contains at most 4 values of n." some1 can explain why? I think on each depth contain 4^h values

»
11 лет назад, скрыть # |
Rev. 3  
Проголосовать: нравится 0 Проголосовать: не нравится

*

»
11 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

I don't undertand different in two initialization:

F[0]=1; F[1]=1; cout<<f(n);
///////////////////// F[0]=1; F[1]=2; cout<<f(n-1);

»
10 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Is this better(efficient) than matrix exponentiation to calculate fibonacci??

please clarify me??

  • »
    »
    10 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    Similar in time complexity. Faster to code if you code matrix multiplication each time in a fibonacci question or slower if you use pre-written library for that. Hence, also faster/slower in performance depending upon your matrix multiplication code.

    Key takeaway — If you write code from scratch each time and only have to code fibonacci use this else use pre-written matrix multiplication.

»
10 лет назад, скрыть # |
 
Проголосовать: нравится +8 Проголосовать: не нравится

How to do it when there is variation in Fibonacci series. For ex — F(n) = 2*F(n-1) + 3*F(n-2)

  • »
    »
    10 лет назад, скрыть # ^ |
    Rev. 2  
    Проголосовать: нравится +5 Проголосовать: не нравится

    This code works for the case F[0]=1, F[1]=2:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define long long long
    const int M = 1000000007;
    map<long, long> F;
    
    long f(long n) {
    	if (F.count(n)) return F[n];
    	long n1=n/2, n2=n-n1;
    	return F[n] = (f(n1)*f(n2) + f(n1-1)*3*f(n2-1)) % M;
    }
    
    main() {
    	F[0]=1; F[1]=2;
    	for (int i=0; i<10; i++)
    		cout << f(i) << endl;
    	cout << f(1000000000000000000LL) << endl;
    }
    
    

    If we choose different initial values, we need to make some modifications. The following code works for the case F[0]=200, F[1]=300:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define long long long
    const int M = 1000000007;
    map<long, long> F, G;
    
    long f(long n) {
    	if (F.count(n)) return F[n];
    	long n1=n/2, n2=n-n1;
    	return F[n] = (f(n1)*f(n2) + f(n1-1)*3*f(n2-1)) % M;
    }
    
    long g(long n) {
    	if (G.count(n)) return G[n];
    	long n1=n/2, n2=n-n1;
    	return G[n] = (g(n1)*f(n2) + g(n1-1)*3*f(n2-1)) % M;
    }
    
    main() {
    	F[0]=1; F[1]=2;
    	G[0]=200; G[1]=300;
    	for (int i=0; i<10; i++)
    		cout << g(i) << endl;
    	cout << g(1000000000000000000LL) << endl;
    }
    
»
9 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

How can we prove the complexity of this algorithm?

»
9 лет назад, скрыть # |
 
Проголосовать: нравится -31 Проголосовать: не нравится

i want to know how many time author spent in coma , because author of this post tell such stupid and wide known facts

»
8 лет назад, скрыть # |
Rev. 2  
Проголосовать: нравится +1 Проголосовать: не нравится

This Formula has been posted in Geek for Geek, hasn't it?

»
6 лет назад, скрыть # |
 
Проголосовать: нравится -12 Проголосовать: не нравится

Can someone explain why this code gets wrong answer if $$$ n=10^{19} $$$.
Try this nth Fibonacci problem

»
6 лет назад, скрыть # |
 
Проголосовать: нравится +24 Проголосовать: не нравится

I’m not sure if people have said it already, but this is actually the same solution as matrix multiplication (only an optimization for the particular form of the recurrence matrix). More specifically, you may notice that matrices of form $$$F(a, b) = [[a, b], [b, a+b]]$$$ form a subring of matrices.

  • $$$F(a, b) + F(a’, b’) = F(a+a’, b + b’)$$$
  • $$$F(a, b) * F(a’, b’) = F(a a’ + b b’, a b’ + b (a’ + b’))$$$

You can prove the above by arithmetic. In particular, identity is $$$F(1, 0)$$$, and Fibonacci matrix is $$$F(0, 1)$$$. This means that instead of storing the $$$2x2$$$ matrix, you could store just $$$a$$$ and $$$b$$$. This explains the formula and generalizes it.

»
3 года назад, скрыть # |
 
Проголосовать: нравится -17 Проголосовать: не нравится

Nice approach, We can also use Golden ratio stuff but it will give approx value, as we know that ratio of two consecutive fibonacci no. is nearly equal to golden-ratio.