Period
Difficulty: Hard

You are given 2 integers **a** and **b**. Let a number be defined as 
![image1](https://s3.amazonaws.com/hr-assets/0/1526567764-7f13ff1150-period1.png). As we know ![image1](https://s3.amazonaws.com/hr-assets/0/1526567764-7f13ff1150-period1.png) will be an irrational number when b is non-zero. In this problem, we call it the AC number. We define 

![Image2](https://s3.amazonaws.com/hr-assets/0/1526567811-db0dd614fb-period2.png) (where x an integer)<br /><br /> and the operation ![Image3](https://s3.amazonaws.com/hr-assets/0/1526567834-0366f2bad1-perioda.png) on AC number as:

![Image4](https://s3.amazonaws.com/hr-assets/0/1526567862-8b1090f7e1-period4.png)

This problem is to find the smallest positive integer **n**, such that:

![Image5](https://s3.amazonaws.com/hr-assets/0/1526567879-29dc56cbe4-period5.png)

We call the integer **n** as period. You are given **a**, **b** and **m**. Can you figure out the period?

**Input Format**  
The first line of the input contains a single integer T denoting the number of test-cases.   
T lines follow, each containing 3 integers - a, b and m separated by a single space. 

**Output Format**  
Output the Period if it exists, otherwise output "-1" (quotes only for reference)

**Constraints**  
1 ≤ T ≤ 300  
5 ≤ m ≤ 10<sup>7</sup>  
0 ≤ a, b < m


**Sample Input #00**

    4
    0 0 13
    1 0 7
    3 0 10007
    1 1 19

**Sample Output #00**

    -1
    1
    5003
    18
    
**Explanation #00**   

For the 1st test-case, no amount of operation ⊗ on a = 0, b = 0 gives 1 on the RHS. Hence the answer is -1.   
When a = 1, b = 0, we have 1 for n = 1.  
On repeated operations, the third and the fourth testcases sum to 1 for n = 5003 and n = 18 respectively. 


Input Format:

Output Format:

Sample Input:

Sample Output:

Python 3 starter code:

Editorial: Period : Oct 2020 Editorial
<style id="MathJax_SVG_styles">.MathJax_SVG_Display {text-align: center; margin: 1em 0em; position: relative; display: block!important; text-indent: 0; max-width: none; max-height: none; min-width: 0; min-height: 0; width: 100%}
.MathJax_SVG .MJX-monospace {font-family: monospace}
.MathJax_SVG .MJX-sans-serif {font-family: sans-serif}
.MathJax_SVG {display: inline; font-style: normal; font-weight: normal; line-height: normal; font-size: 100%; font-size-adjust: none; text-indent: 0; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0; min-height: 0; border: 0; padding: 0; margin: 0}
.MathJax_SVG * {transition: none; -webkit-transition: none; -moz-transition: none; -ms-transition: none; -o-transition: none}
.mjx-svg-href {fill: blue; stroke: blue}
</style><svg style="display: none;"><defs id="MathJax_SVG_glyphs"></defs></svg><p><strong>Problem</strong> <a href="https://www.hackerrank.com/contests/oct13/challenges/period">Period</a></p>

<p><strong>Difficulty</strong> : Medium-Hard</p>

<p><strong>Required Knowledge</strong> : Group Theory, Euler's Criterion, Lagrange's theorem</p>

<p><strong>Problem Setter</strong> : <a href="https://www.hackerrank.com/AekdyCoin">AekDy Coin</a></p>

<p><strong>Problem Tester</strong> : <a href="https://www.hackerrank.com/cpcs">Cao Peng</a></p>

<p><strong>Approach</strong></p>

<p>For one given P, the AC number <img src="https://hr-filepicker.s3.amazonaws.com/period1.png" alt="image1" title=""> that satisfies 0 ≤ a,b &lt; p
and a<sup>2</sup> ≅ 5b<sup>2</sup>(mod P) have th property:</p>

<p>Suppose, </p>

<p>∀n ∈ Z<sup>+</sup>, <br>
(a + b√5)<sup>n</sup> = c + d√5</p>

<p>Then we have c<sup>2</sup> = 5d<sup>2</sup>(mod P) <br>
Quite obvious by mathematical induction.
So if a<sup>2</sup> ≅5b<sup>2</sup>(mod P), we could not find the Period since the expected result AC number is with c=1 and d = 0.</p>

<p>So for the remaindering AC number, we have a<sup>2</sup>≠5b<sup>2</sup>(mod P) <br>
If 5 is one quadratic residue modulo P, then we can find (P-1)<sup>2</sup> such unique AC number satisfy. a<sup>2</sup>≠5b<sup>2</sup>(mod P) </p>

<p>Proof:</p>

<p>If 5 is one quadratic residue modulo P , then for the <a href="https://en.wikipedia.org/wiki/Primitive_root_modulo_n">primitive root</a> <strong>g</strong>, we have </p>

<p>g<sup>2k</sup> ≅5(mod P) the AC number such that a<sup>2</sup>≅5b<sup>2</sup>(mod P) must satisfy:</p>

<p>g<sup>2I(a)</sup>≅g<sup>2k</sup>g<sup>2I(b)</sup>(mod P), which means </p>

<p>2I(a)≅2(k+I(b))(mod P - 1), there are totally 2(P-1) AC number that satisfy that condition. (which means they also satisfy </p>

<p>a<sup>2</sup>≅5b<sup>2</sup>(mod P), but don't forget 0 + 0√5, so there are </p>

<p>P<sup>2</sup> - 2(P-1) - 1 = (P-1)<sup>2</sup> AC numbers such that a<sup>2</sup>≠5b<sup>2</sup>(mod P) </p>

<p>If 5 is not one quadratic residue modulo P, then we can find P<sup>2</sup> - 1 = (P-1)(P+1) such unique AC number satisfies, </p>

<p>a<sup>2</sup>≠5b<sup>2</sup>(mod P), because only one AC number o + 0√5 satisfies, </p>

<p>a<sup>2</sup>≅5b<sup>2</sup>(mod P) </p>

<p>We can use <a href="https://en.wikipedia.org/wiki/Euler%27s_criterion">Euler's Criterion</a> to judge whether 5 is one quadratic residue modulo P in O(logP) time.
The identity element in this group is 1.
However there are other 2 properties that guarantee it is a group. I will ignore the proof here.</p>

<p>Finally, base one [Lagrange's Theorem)(<a href="http://en.wikipedia.org/wiki/Lagrange%27s_theorem_(group_theory)">http://en.wikipedia.org/wiki/Lagrange%27s_theorem_(group_theory)</a>) we have 
Period C, where C is the number of AC number satisfies 
a<sup>2</sup>≠5b<sup>2</sup>(mod P). Simple brute force will work. </p>

<p><strong>Setter's Code</strong></p>

<pre><code>#include&lt;iostream&gt;
#include&lt;queue&gt;
#include&lt;cstdio&gt;
#include&lt;cmath&gt;
#include&lt;string&gt;
#include&lt;vector&gt;
#include&lt;algorithm&gt;
#include&lt;stack&gt;
#include&lt;cstring&gt;
#include&lt;map&gt;
using namespace std;

typedef long long LL;
typedef pair&lt;int,int&gt; PII;
#define pb push_back
#define mp make_pair

bool isPrime(int n) {
    if(n==1)return 0;
    for(int i =2; i * i &lt;= n; ++ i) if( n % i == 0 ) return 0;
    return 1;
}

inline LL MOD(LL a, LL b) {a%=b; return a&lt;0?a+b:a;}

LL powmod(LL a, LL b, LL c){
    LL ret = 1%c; a%=c;
    while(b){
        if(b&amp;1)ret=ret*a%c;
        a=a*a%c;
        b&gt;&gt;=1;
    }
    return ret;
}
// P is one prime number
LL inv( LL a, LL p) {return powmod( a, p - 2, p ) ; }

LL P;
class Element {
public:
    LL a, b;
    // a + b Sqrt(5)
    Element(){}
    Element(LL _a, LL _b) :a(_a),b(_b){}
    Element operator+(const Element e) {
        return Element(MOD(a + e.a , P),MOD(b + e.b , P));
    }
    Element operator*(const Element e) {
        return Element(MOD(a*e.a + b*e.b * 5, P),MOD(a*e.b+b*e.a, P));
    }
    Element operator^(LL k){
        if(k==0) return Element(1,0);
        --k;
        Element ret = *this, a = *this;
        while(k){
            if(k&amp;1) ret= ret * a ;
            a = a * a;
            k &gt;&gt;= 1;
        }
        return ret;
    }
    Element inverse(){
        if(!a&amp;&amp;!b) return *this;
        if(b == 0) {
            return Element(inv(a, P) , 0 );
        }
        if(a == 0) {
            return Element(0, inv(5*b%P, P));
        }
        LL iv = inv( MOD(-b,P) , P );
        LL x, y;
        y = inv( iv * (a*a%P) % P + b*5 , P );
        x = (iv * a % P * y) % P;
        return Element( x, y) ;
    }
    bool isZ(){
        return !a &amp;&amp; !b;
    }
    bool isE(){
        return a == 1 &amp;&amp; b == 0;
    }
    bool operator&lt;(const Element e) const {
        if(a == e.a) return b &lt; e.b;
        return a &lt; e.a;
    }
    void rand_gen(){
        do{a = rand()%P; b= rand()%P;}while(0);
    }
    void out(){
        cout &lt;&lt; a &lt;&lt;" " &lt;&lt; b &lt;&lt; endl;
    }
};

// a + b Sqrt(5)
LL circle( Element a ) {
    Element b =a;
    LL c = 1;
    while( ! a.isE( )) {
        a = a * b;
        ++ c;
        //a.out();
        if(a.a == b.a &amp;&amp; a.b == b.b) {
            return - 1;
        }
    }
    return c;
}

bool isRes(LL a, LL P ){
    return powmod(a, (P-1)/2, P) == 1;
}

LL my_solution(Element e , LL P) {
    LL a = e.a, b = e.b;
    if(MOD(a*a-5*b*b,P)==0) return -1;
    LL n = P*P,ans;
    if(isRes(5,P)) {
        n = n - 2*P+1;
    }else -- n;
    ans = n;
    for(LL i = 1; i*i &lt;= n; ++ i) if(n%i == 0) {
        if( (Element(a,b) ^(i)).isE() )
            ans = min(ans, i );
        if( (Element(a,b) ^(n/i)).isE() )
            ans = min(ans, n/i );
    }
    return ans;
}

void dp(){
    while( true ) {
        P = rand()%1000 + 6;
        while(!isPrime(P)) ++ P;
        Element e; e.rand_gen();
        LL my_ans = my_solution(e, P);
        LL bf = circle(e) ;
        static int cas = 0;  ++ cas;
        if(my_ans == bf) {
            cout &lt;&lt;"correct @" &lt;&lt; cas &lt;&lt;" ans = " &lt;&lt; my_ans&lt;&lt; endl;
        }else {
            cout &lt;&lt;"error"&lt;&lt;endl;
            cout &lt;&lt; P &lt;&lt; endl;
            e.out();
            return;
        }
    }
}

Element rand_one_bad(LL P) {
    for (LL a = 1; a &lt; P; ++a)
        for (LL b = 1; b &lt; P; ++b) {
            if (MOD(a * a - 5 * b * b, P) == 0) {
                return Element(a, b);
            }
        }
    return Element(0,0);
}

void gen(int x ){
    char in[] = "input00.in";
    in[6]='0'+x;
    freopen(in,"w", stdout);

    int T = (x+1)*10;
    int LIMIT[] = {100, 10000, 1e6,1e6};
    cout &lt;&lt; T &lt;&lt; endl;
    while(T --) {
        P = rand()% (int)LIMIT[x/3] + 13;
        while(!isPrime(P)) ++ P;
        Element e; e.rand_gen();
        if( P &lt; 1e4 &amp;&amp; isRes(5,P) &amp;&amp; rand()%2 == 0) {
            e = rand_one_bad(P);
        }
        cout &lt;&lt; e.a &lt;&lt;" " &lt;&lt; e.b &lt;&lt;" " &lt;&lt; P &lt;&lt; endl;
    }
}


void run(int x ){
    char in[] = "input00.in";
    char out[] = "output01.out";
    in[6]='0'+x;
    out[7]='0'+x;

    freopen(in,"r",stdin);
    freopen(out,"w", stdout);
    int T ;
    cin &gt;&gt; T;
    while(T --) {
        LL a, b; cin &gt;&gt; a &gt;&gt; b &gt;&gt; P;
        if(!isPrime(P) || P &lt;= 5 || a &gt;= P || b &gt;= P || a &lt; 0 || b &lt; 0) {
            cerr &lt;&lt;"SB" &lt;&lt; endl;
            exit(0);
        }
        cout &lt;&lt; my_solution( Element(a,b), P) &lt;&lt; endl;
    }
}

void _cmp_with_bf(int x ){
    char in[] = "input00.in";
    char out[] = "output01.out";
    in[6]='0'+x;
    out[7]='0'+x;

    freopen(in,"r",stdin);

    int T ,cas = 0;
    cin &gt;&gt; T;
    while(T --) {
        LL a, b; cin &gt;&gt; a &gt;&gt; b &gt;&gt; P;
        if(!isPrime(P) || P &lt;= 5 || a &gt;= P || b &gt;= P || a &lt; 0 || b &lt; 0) {
            cerr &lt;&lt;"SB" &lt;&lt; endl;
            exit(0);
        }
        LL my =  my_solution( Element(a,b), P) ;
        LL bf = circle( Element(a,b) ) ;
        if(my != bf) {
            cout &lt;&lt;"SB"&lt;&lt;endl;
            cout &lt;&lt; a &lt;&lt;" " &lt;&lt; b &lt;&lt;" " &lt;&lt; P &lt;&lt; endl;
            cout &lt;&lt;my &lt;&lt;" " &lt;&lt; bf &lt;&lt; endl;
            exit(0);
        }
        cout &lt;&lt;"correct @" &lt;&lt; x &lt;&lt;"  case " &lt;&lt; cas ++ &lt;&lt; endl;
    }
}
int main() {
    srand( time( NULL )) ;
    //  for(int i = 0; i &lt; 10;++i) gen(i);
    //  for(int i = 0; i &lt; 10; ++ i) run(i);
//  for(int i=0;i&lt;10;++i) _cmp_with_bf(i);
    int T ;
    cin &gt;&gt; T;
    while(T --) {
        LL a, b; cin &gt;&gt; a &gt;&gt; b &gt;&gt; P;
        if(!isPrime(P) || P &lt;= 5 || a &gt;= P || b &gt;= P || a &lt; 0 || b &lt; 0) {
            cerr &lt;&lt;"SB" &lt;&lt; endl;
            exit(0);
        }
        cout &lt;&lt; my_solution( Element(a,b), P) &lt;&lt; endl;
    }
    return 0;
}
</code></pre>

<p><strong>Tester's Code</strong></p>

<pre><code>#include &lt;cmath&gt;
#include &lt;cstdio&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;algorithm&gt;
using namespace std;

typedef long long ll;

int mul(ll x,ll y,int p) {
    return x * y % p;
}

int powermod(ll x,ll y,int p) {  //x ^ y mod p
    if (x == 0) {
        return 0;
    }
    if (y == 0) {
        return 1;
    }
    if (y &amp; 1) {
        return mul(powermod(x, y ^ 1, p), x, p);
    }
    x = powermod(x, y &gt;&gt; 1, p);
    return mul(x, x, p);
}

pair&lt;int,int&gt; help(int a,int b,ll x,int p) { // (a + b  * sqrt(5)) ^ n mod p
    if (x == 0) {
        return make_pair(1, 0);
    }
    pair&lt;int,int&gt; A, B;
    if (x &amp; 1) {
        A = help(a, b, x - 1, p);
        B = make_pair(a, b);
    }
    else {
        A = B = help(a, b, x &gt;&gt; 1, p);
    }
    a = mul(A.first, B.first, p) + mul(5, mul(A.second,B.second, p), p);
    if (a &gt;= p) {
        a -= p;
    }
    b = mul(A.first, B.second, p) + mul(A.second , B.first, p);
    if (b &gt;= p) {
        b -= p;
    }
    return make_pair(a, b);
}


int main() {
    /* Enter your code here. Read input from STDIN. Print output to STDOUT */   
int z;
    for (scanf("%d",&amp;z);z;--z) {
        int a,b,p;
        ll x;
        scanf("%d%d%d",&amp;a,&amp;b,&amp;p);
        if (mul(a,a,p) == mul(mul(b,b,p),5,p)) {
            puts("-1");
            continue;
        }
        else if (powermod(5, p &gt;&gt; 1, p) == 1) {
            x = p - 1;
            x *= (p - 1);


        }
        else {
            x = p;
            x *= x;
            --x;
        }
        ll answer = -1;
        pair&lt;int,int&gt; temp;
        for (ll i = 1; i * i &lt;= x; ++i) {
            if (x % i) {
                continue;
            }
            if ((answer &lt; 0) || (i &lt; answer)) {
                temp = help(a,b,i,p);
                if ((temp.first == 1) &amp;&amp; (temp.second == 0)) {
                    answer = i;
                }
            }
            if ((answer &lt; 0) || (x / i &lt; answer)) {
                temp = help(a,b,x / i,p);
                if ((temp.first == 1) &amp;&amp; (temp.second == 0)) {
                    answer = x / i;
                }

            }
        }
        printf("%lld\n",answer);

    }
    return 0;
}
</code></pre>

Reference solution (C++):
###C++  
```cpp  
#include<iostream>
#include<queue>
#include<cstdio>
#include<cmath>
#include<string>
#include<vector>
#include<algorithm>
#include<stack>
#include<cstring>
#include<map>
using namespace std;
    
typedef long long LL;
typedef pair<int,int> PII;
#define pb push_back
#define mp make_pair
    
bool isPrime(int n) {
    if(n==1)return 0;
    for(int i =2; i * i <= n; ++ i) if( n % i == 0 ) return 0;
    return 1;
}
    
inline LL MOD(LL a, LL b) {a%=b; return a<0?a+b:a;}
    
LL powmod(LL a, LL b, LL c){
    LL ret = 1%c; a%=c;
    while(b){
        if(b&1)ret=ret*a%c;
        a=a*a%c;
        b>>=1;
    }
    return ret;
}
// P is one prime number
LL inv( LL a, LL p) {return powmod( a, p - 2, p ) ; }
    
LL P;
class Element {
public:
    LL a, b;
    // a + b Sqrt(5)
    Element(){}
    Element(LL _a, LL _b) :a(_a),b(_b){}
    Element operator+(const Element e) {
        return Element(MOD(a + e.a , P),MOD(b + e.b , P));
    }
    Element operator*(const Element e) {
        return Element(MOD(a*e.a + b*e.b * 5, P),MOD(a*e.b+b*e.a, P));
    }
    Element operator^(LL k){
        if(k==0) return Element(1,0);
        --k;
        Element ret = *this, a = *this;
        while(k){
            if(k&1) ret= ret * a ;
            a = a * a;
            k >>= 1;
        }
        return ret;
    }
    Element inverse(){
        if(!a&&!b) return *this;
        if(b == 0) {
            return Element(inv(a, P) , 0 );
        }
        if(a == 0) {
            return Element(0, inv(5*b%P, P));
        }
        LL iv = inv( MOD(-b,P) , P );
        LL x, y;
        y = inv( iv * (a*a%P) % P + b*5 , P );
        x = (iv * a % P * y) % P;
        return Element( x, y) ;
    }
    bool isZ(){
        return !a && !b;
    }
    bool isE(){
        return a == 1 && b == 0;
    }
    bool operator<(const Element e) const {
        if(a == e.a) return b < e.b;
        return a < e.a;
    }
    void rand_gen(){
        do{a = rand()%P; b= rand()%P;}while(0);
    }
    void out(){
        cout << a <<" " << b << endl;
    }
};
    
// a + b Sqrt(5)
LL circle( Element a ) {
    Element b =a;
    LL c = 1;
    while( ! a.isE( )) {
        a = a * b;
        ++ c;
        //a.out();
        if(a.a == b.a && a.b == b.b) {
            return - 1;
        }
    }
    return c;
}
    
bool isRes(LL a, LL P ){
    return powmod(a, (P-1)/2, P) == 1;
}
    
LL my_solution(Element e , LL P) {
    LL a = e.a, b = e.b;
    if(MOD(a*a-5*b*b,P)==0) return -1;
    LL n = P*P,ans;
    if(isRes(5,P)) {
        n = n - 2*P+1;
    }else -- n;
    ans = n;
    for(LL i = 1; i*i <= n; ++ i) if(n%i == 0) {
        if( (Element(a,b) ^(i)).isE() )
            ans = min(ans, i );
        if( (Element(a,b) ^(n/i)).isE() )
            ans = min(ans, n/i );
    }
    return ans;
}
    
void dp(){
    while( true ) {
        P = rand()%1000 + 6;
        while(!isPrime(P)) ++ P;
        Element e; e.rand_gen();
        LL my_ans = my_solution(e, P);
        LL bf = circle(e) ;
        static int cas = 0;  ++ cas;
        if(my_ans == bf) {
            cout <<"correct @" << cas <<" ans = " << my_ans<< endl;
        }else {
            cout <<"error"<<endl;
            cout << P << endl;
            e.out();
            return;
        }
    }
}
    
Element rand_one_bad(LL P) {
    for (LL a = 1; a < P; ++a)
        for (LL b = 1; b < P; ++b) {
            if (MOD(a * a - 5 * b * b, P) == 0) {
                return Element(a, b);
            }
        }
    return Element(0,0);
}
    
void gen(int x ){
    char in[] = "input00.in";
    in[6]='0'+x;
    freopen(in,"w", stdout);
    
    int T = (x+1)*10;
    int LIMIT[] = {100, 10000, 1e6,1e6};
    cout << T << endl;
    while(T --) {
        P = rand()% (int)LIMIT[x/3] + 13;
        while(!isPrime(P)) ++ P;
        Element e; e.rand_gen();
        if( P < 1e4 && isRes(5,P) && rand()%2 == 0) {
            e = rand_one_bad(P);
        }
        cout << e.a <<" " << e.b <<" " << P << endl;
    }
}
    
    
void run(int x ){
    char in[] = "input00.in";
    char out[] = "output01.out";
    in[6]='0'+x;
    out[7]='0'+x;
    
    freopen(in,"r",stdin);
    freopen(out,"w", stdout);
    int T ;
    cin >> T;
    while(T --) {
        LL a, b; cin >> a >> b >> P;
        if(!isPrime(P) || P <= 5 || a >= P || b >= P || a < 0 || b < 0) {
            cerr <<"SB" << endl;
            exit(0);
        }
        cout << my_solution( Element(a,b), P) << endl;
    }
}
    
void _cmp_with_bf(int x ){
    char in[] = "input00.in";
    char out[] = "output01.out";
    in[6]='0'+x;
    out[7]='0'+x;
    
    freopen(in,"r",stdin);
    
    int T ,cas = 0;
    cin >> T;
    while(T --) {
        LL a, b; cin >> a >> b >> P;
        if(!isPrime(P) || P <= 5 || a >= P || b >= P || a < 0 || b < 0) {
            cerr <<"SB" << endl;
            exit(0);
        }
        LL my =  my_solution( Element(a,b), P) ;
        LL bf = circle( Element(a,b) ) ;
        if(my != bf) {
            cout <<"SB"<<endl;
            cout << a <<" " << b <<" " << P << endl;
            cout <<my <<" " << bf << endl;
            exit(0);
        }
        cout <<"correct @" << x <<"  case " << cas ++ << endl;
    }
}
int main() {
    srand( time( NULL )) ;
    //    for(int i = 0; i < 10;++i) gen(i);
    //    for(int i = 0; i < 10; ++ i) run(i);
//    for(int i=0;i<10;++i) _cmp_with_bf(i);
    int T ;
    cin >> T;
    while(T --) {
        LL a, b; cin >> a >> b >> P;
        if(!isPrime(P) || P <= 5 || a >= P || b >= P || a < 0 || b < 0) {
            cerr <<"SB" << endl;
            exit(0);
        }
        cout << my_solution( Element(a,b), P) << endl;
    }
    return 0;
}
```