Devu Vs Police
Difficulty: Hard

  
It is holi festival, festival of colors. Devu is having fun playing holi and is throwing balloons with his girlfriend Glynis. Police saw this mischief and tried arresting his girlfriend, Devu being a mathematician asked police not to arrest his girlfriend and instead torture him with brain teaser. Devu was a young engineering fellow and he did not knew that policeman was equally good in mathematics, policeman gave Devu a problem which is as follows:

Let $f(n,k) = n^k$

Your aim is to answer $f(n_1,k_1)^{f(n_2,k_2)} \bmod n$

Can you help devu and his girlfriend rescue from modern police.


Input Format:
You are given $T$ which is the number of queries to solve.

Each Query consist of 5 space separated integers $n_1,k_1,n_2,k_2,n$

Output Format:
Output contains exactly $T$ lines. $i^{\text{th}}$ line containing the answer for the $i^{\text{th}}$ query.

Sample Input:
	1
    2 1 2 2 15

Sample Output:
	1

Python 3 starter code:
#
# Complete the 'solve' function below.
#
# The function is expected to return an INTEGER.
# The function accepts following parameters:
#  1. INTEGER n1
#  2. INTEGER k1
#  3. INTEGER n2
#  4. INTEGER k2
#  5. INTEGER n
#

def solve(n1, k1, n2, k2, n):
    # Write your code here



Editorial: Devu Vs Police Infinitum Mar14 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}
.MathJax_SVG_LineBox {display: table!important}
.MathJax_SVG_LineBox span {display: table-cell!important; width: 10000em!important; min-width: 0; max-width: none; padding: 0; border: 0; margin: 0}
</style><svg style="display: none;"><defs id="MathJax_SVG_glyphs"></defs></svg><p><a href="https://www.hackerrank.com/contests/infinitum-mar14/challenges/devu-police">Problem Statement</a>  </p>

<p><strong>Problem Setter</strong> : <a href="http://hackerrank.com/devuy11">Devendra</a> <br>
<strong>Problem Tester</strong> : <a href="http://hackerrank.com/cpcs">Cao Peng</a> <br>
<strong>Required Knowledge</strong>: Chinese Remainder Theorm    </p>

<p>The Basic Idea Exploited here is Chinese Remainder Theorom.<br>
let n = p[1]^e[1] * p[2]^e[2] * p[3]^e[3] <em>...</em> p[k]^e[k] where p[i] is prime.<br>
let expr = A[1]^A[2]^A[3] where A[1] = f(n1,k1) , A[2] = n2, A[3] = k2<br> 
so, calculating expr mod n is equivalent in calculating<br>
CRT ( expr mod p[1]^e[1] , expr mod p[2]^[e_2] ,......., expr mod p[k]^e[k] )<br>
Now lets see the case when e[i] = 1, then calculating expr mod p[i]  is equivalent to A[1]^( A[2]^A[3] mod (p[i] -1 ) ) mod p[i].<br>
Euler Totient Period for p[i] is p[i] - 1.<br>
Now for the case of p[i]^e[i] where e[i]!=1, euler totient period is given by p[i]^e[i] - p[i]^(e[i]-1)<br>
<strong>Note:</strong> :Be carefull with Euler Totient period concept which is valid only if A[1] is coprime to p[i]. It is left as an exercise for the reader to figure it out how to procede then.<br></p>

<p><strong>Solution</strong> by <a href="http://hackerrank.com/cpcs">cpcs</a>  </p>

<p>Let a = n1<sup>k1</sup> % n and b = n2<sup>k2</sup>, we need to calculate a^b mod n. We can judge whether a = 0/1 or b = 0,1 first to deal with the special conditions like 0^0, 1^p...etc. <br>
Then we can suppose a &gt; 1 and b &gt; 1. <br>
The solution is based on that although n may not be a prime, the period of the n1<sup>x</sup> % n is phi(n) , where phi is the euler function. <br>
But the starting point of the first period may be starts from phi(n).  That means for any y &gt;= phi(n) we have n1<sup>(y)</sup> == n1<sup>(y + phi(n))</sup>  (mod n)  </p>

<p>So if we found b is smaller enough, namely if b &lt; phi(n), we can directly calculate the result using O(logb) algorithm. Otherwise we have b&gt;=phi(n) then n1<sup>k1</sup> == n1<sup>(b % phi(n) + phi(n))</sup>  mod n, so we just calculate n1 <sup>(b % phi(n) + phi(n))</sup> % n. </p>

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

<pre><code>#include&lt;stdio.h&gt;
#include&lt;iostream&gt;
#include&lt;string.h&gt;
#include&lt;vector&gt;
#include&lt;assert.h&gt;
using namespace std;
typedef long long int ll;
int sieve_par=3162;
int prime[3162] , array[3162],counter=0;
ll inverse(ll a,ll b)                   //b&gt;a
{
    ll Remainder,p0=0,p1=1,pcurr=1,q,m=b;
    while(a!=0)
    {
        Remainder=b%a;
        q=b/a;
        if(Remainder!=0)
        {
            pcurr=p0-(p1*q)%m;
            if(pcurr&lt;0)
                pcurr+=m;
            p0=p1;
            p1=pcurr;
        }
        b=a;
        a=Remainder;
    }
    return pcurr;
}
ll binpow(ll a,ll b,ll mod)
{
    ll ans=1;
    while(b)
        if(b&amp;1){
            ans=(ans*a)%mod;
            b--;

        }
        else{   
            a=(a*a)%mod;
            b&gt;&gt;=1;
        }
    return ans%mod;
}
ll CRT(ll mod[],ll rem[],int t)         //t is the number of pairs of rem and mod
{
    ll ans = rem[0],m = mod[0];

    for(int i = 1;i &lt; t;++i)
    {
        ll a = inverse(m,mod[i]);
        ll b = inverse(mod[i],m);
        ans = (ans * b * mod[i] + rem[i] * a * m) % (m * mod[i]);
        m *= mod[i];
    }   
    return ans;
}
void sieve()
{
    for(int i=1;i&lt;sieve_par;i++)
        array[i]=1;
    array[0]=0;
    int j;
    for(int i=2;i&lt;=sieve_par;i++)
    {
        if(array[i-1]==1)
        {
            prime[counter]=i;
            for(j=i*i;j&lt;=sieve_par;j+=i)
                array[j-1]=0;
            counter++;
        }
    }
}
int check(ll a,ll b,ll n)
{
    ll ans=1;
    while(b)
        if(b&amp;1){
            ans=ans*a;
            if(ans&gt;n)   return -1;
            b--;
        }
        else{
            a=a*a;
            if(a&gt;n)     return -1;
            b&gt;&gt;=1;  
        }
    return ans;
}
ll solveit(int n1,int k1,int n2,int k2,int m,int p)
{
    ll x=1,y=0;
    if(n1==0){
        if(n2==0 &amp;&amp; k2==0 &amp;&amp; k1==0) return 1;
        if(n2==0 &amp;&amp; k2==0 &amp;&amp; k1!=0) return 0;
        if(k1==0 || n2==0)  return 1;
        return 0;
    }
    if(n1 % p == 0 ){
        ll ans;
        while(n1%p == 0){
            n1/=p;
            x=x*p;
            y++;
        }
        ans= check(n2,k2,m);
        ans= ans* k1*y;
        if(ans&gt;=0)  ans= check(p,ans,m);
        if(ans&lt;0)   return 0;
        else x= ans;
    }
    ll a=binpow(n2,k2,m-(m/p));
    ll b=binpow(n1,k1,m);
    ll c= binpow(b,a,m);
    return (c*x)%m;
}
int main()
{
    sieve();
    int test,n1,n2,n,k1,k2,t;
    ll mod[15],rem[15],ans;
    //printf("%d is counter\n",counter);    
    scanf("%d",&amp;test);
    assert(test&lt;=10000);
    while(test--){
        scanf("%d%d%d%d%d",&amp;n1,&amp;k1,&amp;n2,&amp;k2,&amp;n);
        assert(n1&lt;=1000000000 &amp;&amp;  k1&lt;=1000000000 &amp;&amp; n2&lt;=1000000000 &amp;&amp; k2&lt;=1000000000 &amp;&amp; n&lt;=10000000);
        assert(n1&gt;=0 &amp;&amp; k1&gt;=0 &amp;&amp; n2&gt;=0 &amp;&amp; k2&gt;=0 &amp;&amp; n&gt;=1);
        if(n==1){
            printf("0\n");
            continue;
        }
        t=0;
        for(int i=0;i&lt;counter;i++){
            if(n&lt; prime[i]*prime[i])    break;
            if(n%prime[i]==0){
                mod[t]=1;
                while(n%prime[i]==0){
                    n/=prime[i];
                    mod[t]*=prime[i];
                }
                rem[t]=solveit(n1,k1,n2,k2,mod[t],prime[i]);
                t++;
            }
        }
        if(n&gt;1){
            mod[t]=n;
            rem[t]=solveit(n1,k1,n2,k2,mod[t],n);
            t++;
        }
        printf("%lld\n",CRT(mod,rem,t));
    }
    return 0;
}
</code></pre>

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

<pre><code>import java.math.*;
import java.util.*;



public class Solution {
    public static long powermod(long x,long y,long M) {
      x %= M;

      if (y == 0) {
        return 1;
      }
      if (x == 0) {
        return 0;
      }
      long r = 1L;
      for (;y &gt; 0; y &gt;&gt;= 1) {
        if ((y &amp; 1) &gt; 0) {
            r = r * x % M;
        }
        x = x * x % M;
      }
      return r;
    }
    public static long phi(long m) {
      long p = 1L;
       for (long i = 2L; i * i &lt;= m; ++i) {
        if (m % i == 0) {
            long j = 1L;
             while (m % i == 0) {
                m /= i;
                j *= i;
             }

             p *= j - j / i;
        }
      }
      return (m &gt; 1)?(p * (m - 1)):p;
    }
    public static long cmp(long n,long k,long x) {  //n ^ k &gt; x &lt; x = x
    long i = 0L, temp = 1L;
        while ((i &lt; k) &amp;&amp; (temp &lt; x)) {
           i++;
           temp *= n;
        }
        if ((i &gt;= k) &amp;&amp; (temp &lt;= x)) {
          return temp;
        }
        return -1;

    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        for (int cases = scanner.nextInt(); cases &gt; 0; cases--) {
          long n1 = scanner.nextLong();
          long k1 = scanner.nextLong();
          long n2 = scanner.nextLong();
          long k2 = scanner.nextLong();
          long n = scanner.nextLong();
          if (n == 1) {
            System.out.println(0);
          }
          else {
            long x = powermod(n1,k1,n);
            if ((k2 == 0) || (n2 == 1)) {
              System.out.println(x);
            }
            else if (n2 == 0) {
              System.out.println(1);
            }
            else if (x &lt;= 1) {
                 System.out.println(x);
            }
            else {  // n2 &gt; 1, k2 &gt; 0, x &gt; 1
              long p = phi(n);
              long y = cmp(n2,k2,p);
              System.out.println(powermod(x, (y &gt;= 0)?y:(powermod(n2,k2,p) + p),n));

            }

          }
        }

    }
}
</code></pre>

Reference solution (C++):
###C++  
```cpp  


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<vector>
#include<assert.h>
using namespace std;
typedef long long int ll;
int sieve_par=3162;
int prime[3162] , array[3162],counter=0;
ll inverse(ll a,ll b)                    //b>a
{
    ll Remainder,p0=0,p1=1,pcurr=1,q,m=b;
    while(a!=0)
    {
        Remainder=b%a;
        q=b/a;
        if(Remainder!=0)
        {
            pcurr=p0-(p1*q)%m;
            if(pcurr<0)
                pcurr+=m;
            p0=p1;
            p1=pcurr;
        }
        b=a;
        a=Remainder;
    }
    return pcurr;
}
ll binpow(ll a,ll b,ll mod)
{
    ll ans=1;
    while(b)
        if(b&1){
            ans=(ans*a)%mod;
            b--;
    
        }
        else{    
            a=(a*a)%mod;
            b>>=1;
        }
    return ans%mod;
}
ll CRT(ll mod[],ll rem[],int t)            //t is the number of pairs of rem and mod
{
    ll ans = rem[0],m = mod[0];
    
    for(int i = 1;i < t;++i)
    {
        ll a = inverse(m,mod[i]);
        ll b = inverse(mod[i],m);
        ans = (ans * b * mod[i] + rem[i] * a * m) % (m * mod[i]);
        m *= mod[i];
    }   
    return ans;
}
void sieve()
{
    for(int i=1;i<sieve_par;i++)
        array[i]=1;
    array[0]=0;
    int j;
    for(int i=2;i<=sieve_par;i++)
    {
        if(array[i-1]==1)
        {
            prime[counter]=i;
            for(j=i*i;j<=sieve_par;j+=i)
                array[j-1]=0;
            counter++;
        }
    }
}
int check(ll a,ll b,ll n)
{
    ll ans=1;
    while(b)
        if(b&1){
            ans=ans*a;
            if(ans>n)    return -1;
            b--;
        }
        else{
            a=a*a;
            if(a>n)        return -1;
            b>>=1;    
        }
    return ans;
}
ll solveit(int n1,int k1,int n2,int k2,int m,int p)
{
    ll x=1,y=0;
    if(n1==0){
        if(n2==0 && k2==0 && k1==0)    return 1;
        if(n2==0 && k2==0 && k1!=0)    return 0;
        if(k1==0 || n2==0)    return 1;
        return 0;
    }
    if(n1 % p == 0 ){
        ll ans;
        while(n1%p == 0){
            n1/=p;
            x=x*p;
            y++;
        }
        ans= check(n2,k2,m);
        ans= ans* k1*y;
        if(ans>=0)    ans= check(p,ans,m);
        if(ans<0)    return 0;
        else x= ans;
    }
    ll a=binpow(n2,k2,m-(m/p));
    ll b=binpow(n1,k1,m);
    ll c= binpow(b,a,m);
    return (c*x)%m;
}
int main()
{
    sieve();
    int test,n1,n2,n,k1,k2,t;
    ll mod[15],rem[15],ans;
    //printf("%d is counter\n",counter);    
    scanf("%d",&test);
    assert(test<=10000);
    while(test--){
        scanf("%d%d%d%d%d",&n1,&k1,&n2,&k2,&n);
        assert(n1<=1000000000 &&  k1<=1000000000 && n2<=1000000000 && k2<=1000000000 && n<=10000000);
        assert(n1>=0 && k1>=0 && n2>=0 && k2>=0 && n>=1);
        if(n==1){
            printf("0\n");
            continue;
        }
        t=0;
        for(int i=0;i<counter;i++){
            if(n< prime[i]*prime[i])    break;
            if(n%prime[i]==0){
                mod[t]=1;
                while(n%prime[i]==0){
                    n/=prime[i];
                    mod[t]*=prime[i];
                }
                rem[t]=solveit(n1,k1,n2,k2,mod[t],prime[i]);
                t++;
            }
        }
        if(n>1){
            mod[t]=n;
            rem[t]=solveit(n1,k1,n2,k2,mod[t],n);
            t++;
        }
        printf("%lld\n",CRT(mod,rem,t));
    }
    return 0;
}
```