LG4000 Fibonacci number matrix fast power, randomized

Foreword

You open the title "P4000 Fibonacci number";

You've found is written \ (\ mathrm {998244853} \ ) passes seek \ (\ mathrm {Fib} _n \) ;

You skillfully write and submit a power of rapid matrix;

You get a version of the \ (\ mathrm TLE} {\) , since \ (n-\ Leq 30000000 10 ^ {} \) ;

You point to open the solution to a problem, find a solution to a problem first post large formulas and theorems;

You slide the screen down, other explanations are put directly conclusions.

I believe you went through so many hearts full of "me too hard."

Then this problem solution will save you veering into (?)

Front cheese

  • Protagonist: the birthday paradox;
  • Auxiliary Conclusion: modulus \ (P \) Fibonacci loop segment length \ (\ PI (P) \ Leq 6P \) ;
  • \ (O (\ sqrt p) -O (1) \) fast power, LOJ template title .

About accessibility conclusions prove, because the pre-conclusion more (I actually do not)Therefore explanations are omitted in Benpian. If you conditions, reference may be \ ({Wikipedia} \ \ mathrm ) of \ (\ mathrm {Pisano \ Period } \) entries, where there is evidence.

So in fact this practice, there are many front. But on the number compared to pure practice, this conclusion is only one, and this conclusion is easy to remember.

Algorithmic process

One thing is clear is the need to calculate the Fibonacci cycle section of Number of. Violence basic approach does not optimize the space, considered: Set the loop section length \ (\ PI (P) \) , for \ (I \ NEQ J \) , if the \ (\ mathrm {Fib} _i = \ mathrm {Fib} _j \) and \ (\ mathrm {Fib. 1} + I {_} = \ mathrm {Fib. 1} _ {+} J \) , then the \ (\ PI (P) \ MID JI \) . This means that if the two locations to find \ (i, j \) satisfy the condition can get some multiple of the length of the loop section.

Because only demand value, so determined \ (\ pi (p) \ ) true value is not necessary to determine the multiples are also acceptable. Can be obtained by using a new algorithm is randomized: two random numbers every time \ (I, J \) , calculated \ (\ mathrm {Fib} _i , \ mathrm {Fib} _ {i + 1}, \ mathrm {Fib } _j, \ mathrm {Fib} _ {j + 1} \) values determined are equal.

Obviously, this approach is expected \ (O (p) \) , there is no difference with the violence. However, we can describe the problem from a different angle: every two random positions \ (I, J \) , the equivalent of two random numbers \ (x = i \ mod \ pi (p) \) and \ (y = j \ MOD \ PI (P) \) , if \ (x = y \) can find multiple section loop.

This problem can be found consistent with the "birthday paradox" problem. Using the birthday paradox thought, every two random hit probability is very small, but random three, four, a lot of positions, as the number of random growth, hit probability is the square of the level of growth.

We can be obtained a better algorithm: Before using a random hash table to record all \ ((\ mathrm {Fib} _i, \ mathrm {Fib} _ {i + 1}, i) \) triples each random position \ (J \) and get \ ((\ _J mathrm} {Fib, \ mathrm {Fib. 1} _ {+} J, J) \) , if satisfied can be found in the hash table \ (\ mathrm {Fib} _i = \ mathrm {Fib} _j \) and \ (\ mathrm {Fib} _ {i + 1} = \ mathrm {Fib} _ {j + 1} \) triad \ ((\ Fib _i} {mathrm, \ mathrm Fib {_} + {I}. 1, I) \) , can be obtained some multiple section loop.

According to the birthday paradox, the algorithm described above in expectation \ (O (\ sqrt p) \) within the times can be done to find. Use \ (O (\ sqrt p) - O (1) \) Matrix / extension field to achieve rapid power demand Fibonacci numbers, can be done \ (O (\ sqrt p) \) to obtain cycles festival.

After words

This approach is in review Pollard-rhotime algorithmPlaying diaphragmTurn to have a blog record \ (\ pi (p) \ leq 6p \) emerged when. If you encounter a similar problem in the examination room, only faith guess cycle section length of the modulus level, the \ (\ frac {\ text {loop section length}} {\ text {modulus}} \) This constant is estimated larger then apply this approach can be a problem, expand relatively high.

If you want to ask \ (\ pi (p) \ ) number about the true value, just out of the loop section enumerator then one by one to determine.

Show me the Code.

Two implementation details:

  • Community recommendations on random position greater than \ (12p \) , otherwise the desired number of times may be degraded. Random code is bound on \ (2 ^ {36} \) , selected as a power of two modulus (perhaps) may be minimized as a result of modulo mt19937_64random problem of uneven.
  • \ (p <2 ^ {31 } \) can be a directly long longable to save \ ((\ mathrm {Fib} _i, \ mathrm {Fib} _ {i + 1}) \) tuple, then can be used unordered_mapachieve the hash table.

At the same time this code is constant is relatively large, with the constant expansion of the domain will be smaller by half.

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define ull unsigned long long
unordered_map < ull , ll > circ; ll len;
int MOD , MX = 1 << 18; mt19937_64 rnd(time(0));
struct matrix{
    ll arr[2][2];
    matrix(){memset(arr , 0 , sizeof(arr));}
    ll* operator [](int x){return arr[x];}
    friend matrix operator *(matrix p , matrix q){
        matrix x;
        for(int i = 0 ; i < 2 ; ++i)
            for(int j = 0 ; j < 2 ; ++j)
                for(int k = 0 ; k < 2 ; ++k)
                    x[i][k] += p[i][j] * q[j][k];
        for(int i = 0 ; i < 2 ; ++i)
            for(int j = 0 ; j < 2 ; ++j) x[i][j] %= MOD;
        return x;
    }
}G , T[2][1 << 18 | 1];

signed main(){
    static char str[300000003]; scanf("%s %d" , str + 1 , &MOD);
    T[0][0][0][0] = T[0][0][1][1] = T[1][0][0][0] = T[1][0][1][1] = 1;
    T[0][1][0][1] = T[0][1][1][0] = T[0][1][1][1] = 1;
    for(int i = 2 ; i <= MX ; ++i) T[0][i] = T[0][i - 1] * T[0][1];
    T[1][1] = T[0][MX]; for(int i = 2 ; i <= MX ; ++i) T[1][i] = T[1][i - 1] * T[1][1];
    while(1){
        ll x = (rnd() << 28 >> 28); matrix C = T[0][x & (MX - 1)] * T[1][x >> 18];
        ull val = ((1ull * C[0][0]) << 32) | C[0][1];
        if(circ.find(val) != circ.end()){len = abs(circ[val] - x); break;}
        circ[val] = x;
    }
    ll sum = 0; 
    for(int i = 1 ; str[i] ; ++i) sum = (sum * 10 + str[i] - '0') % len;
    cout << (T[0][sum & (MX - 1)] * T[1][sum >> 18])[0][1];
    return 0;
}

Guess you like

Origin www.cnblogs.com/Itst/p/12241180.html