Number Theory
Number Theory
3 Number Theory
In this chapter we are going to talk about important mathematical concepts, theorems and tricks.
Let’s get started.
The Greatest Common Divisor (GCD) of two integers (a, b) denoted by gcd(a,b), is defined as the
largest positive integer d such that d | a and d | b where x | y implies that x divides y.
Example of GCD: gcd(4, 8) = 4, gcd(10, 5) = 5, gcd(20,12) = 4.
Gcd(A,B) = Gcd(B,A%B) // recurrence for gcd
Gcd(A,0) = A // base case
Proof : If a = bq + r.
Let d be any common divisor of a and b which implies d|a and d|b d|(a – bq) d|r.
Let e be any common divisor of b and r e|b , e|r e|(bq + r) e|a. hence any common divisor
of a and b must also be a common divisor of r and any common divisor of b and r must also be a
divisor of a d is a common divisor of a and b iff d is a common divisor of b and r.
Similarly, the LCM of two integers (a, b) denoted by lcm(a,b), is defined as the smallest positive
integer l such that a |l and b | l. Example of LCM : lcm(4,8) = 8, lcm(10,5) = 10, lcm(20,12) = 60.
gcd(a,b) * lcm(a,b) = a*b
The GCD of more than 2 numbers, e.g. gcd(a,b,c) is equal to gcd(a,gcd(b,c)), etc, and similarly for LCM.
Both GCD and LCM algorithms run in O(log(N)), where n = max(a,b).
62
Number Theory
63
Number Theory
Sieve of Eratosthenes
It is easy to find if some number (say N) is prime or not — you simply need to check if at least one
number from numbers lower or equal sqrt(n) is divisor of N. This can be achieved by simple code:
boolean isPrime( int n )
{
if ( n == 1 )
return false; // by definition, 1 is not prime number
if ( n == 2 )
return true; // the only one even prime
for ( int i = 2; i * i <= n; ++i )
if ( n%i == 0 )
return false;
return true;
}
So it takes sqrt(n) steps to check this. Of course you do not need to check all even numbers, so it
can be “optimized” a bit:
boolean isPrime( int n )
{
if ( n == 1 )
return false; // by definition, 1 is not prime number
if ( n == 2 )
return true; // the only one even prime
if ( n%2 == 0 )
return false; // check if is even
for ( int i = 3; i * i <= n; i += 2 ) // for each odd number
if ( n%i == 0 )
return false;
return true;
}
So let say that it takes 0.5sqrt(n) steps*. That means it takes 50,000 steps to check that 10,000,000,000
is a prime.
Time Complexiety :
If we have to check numbers upto N, we have to check each number individually. So time complexity
will be O(Nsqrt(N)).
64
Number Theory
Can we do better?
Ofcourse! we can use a sieve of numbers upto N. For all prime numbers <= sqrt(N), we can make
their multiple non-prime i.e. if p is prime, 2p, 3p, ..., floor(n/p)*p will be non-prime.
Sieve code :
void primes(int *p)
{
for(int i = 2;i<=1000000;i++)
p[i] = 1;
for(int i = 2;i<=1000000;i++)
{
if(p[i])
{
for(int j = 2*i;j<=1000000;j+=i)
{
p[j] = 0;
}
}
}
p[1] = 0;
p[0] = 0;
return;
}
65
Number Theory
}
}
}
p[1] = 0;
p[0] = 0;
return;
}
T = O(NloglogN)
Hence, we have significantly reduced our complexity from N*sqrt(N) to approx linear time.
Optimizations!
we know that all the numbers which are even are non prime except 2.Hence we can mark only odd
numbers as non prime in our sieve and jump to odd numbers always.
Code :
#define lim 10000000
vector <bool> mark(lim+2,1);
vector <ll> primes;
void sieve() // we need primes upto 10^8
{
//ll times = 0;
for(ll i=3;i<=lim;i+=2)
{
//times++;
if(mark[i] == 1)
{
for(ll j=i*i ; j <= lim ;j += 2*i) //skip to odd numbers as i*i is odd
{
mark[j] = 0;
}
}
}
primes.pb(2);
for(ll i=3;i<=lim;i+=2)
{
if(mark[i])
primes.pb(i);
}
}
66
Number Theory
Segmented Sieve
We use this sieve when array of size N does not fit in memory and we want to compute prime numbers
between a range l and r. Example : l = 10 8, r = 10 9.
void sieve()
{
for(int i = 0;i<=1000000;i++)
p[i] = 1;
for(int i = 2;i<=1000000;i++)
{
if(p[i])
{
for(int j = 2*i;j<=1000000;j+=i)
p[j] = 0;
67
Number Theory
}
}
// for(int i=2;i<=20;i++)cout<<i<<“ “<<p[i]<<endl;
}
int segmented_sieve(long long a,long long b)
{
sieve();
bool pp[b-a+1];
memset(pp,1,sizeof(pp));
for(long long i = 2;i*i<=b;i++)
{
for(long long j = a;j<=b;j++)
{
if(p[i])
{
if(j == i)
continue;
if(j % i == 0)
pp[j-a] = 0;
}
}
}
int res = 1;
for(long long i = a;i<b;i++)
res += pp[i-a];
return res;
}
Division
Let a and b be integers. We say a divides b, denoted by a|b, if there exists an integer c such that b= ac.
68
Number Theory
x = (rem[i]*pp[i]*inv[i])) % prod
0 i n 1
Code :
ll chinese_remainder_theorem(vector <ll> num,vector <ll> rem)
{
// find pp vector
vector <ll> pp; // product of all num array except num[i]
pp.clear();
69
Number Theory
ll prod = 1ll;
for(ll i=0;i<num.size();++i)
prod *= num[i];
for(ll i=0;i<num.size();++i)
pp.pb(prod/num[i]);
// find inv[] vector
// inv[i] is modular inverse of pp[i] with respect to num[i]
vector <ll> inv;
inv.clear();
for(ll i=0;i<pp.size();++i)
inv.pb(modular_inverse(pp[i],num[i]-2,num[i]));
// (a^-1)%m when m is prime is (a^(m-2))%m using fermat’s
// now use the sum formula
ll ans = 0ll;
for(ll i=0;i<pp.size();++i)
{
ans = ans%prod + ( ((rem[i]*pp[i])%prod)*(inv[i])%prod )%prod;
ans %= prod;
}
return ans;
}
1 1 1
n n 1 1 . . . 1
p1 p2 pk
Code :
int phi[] = new int[n+1];
for(int i=2; i <= n; i++)
phi[i] = i; //phi[1] is 0
70
Number Theory
Properties :
1. If P is prime then (pk) = (p – 1) p(k – 1).
2. function is multiplicative, i.e. if (a,b) = 1 then (ab) = (a)(b).
3. Let d1, d2, ...dk be all divisors of n (including n). Then (d1) + (d2) + ... + (dk) = n
5. Sum of divisors:
p1a1 1 p2a2 1 p an 1
S(n) ... n
p1 1 p2 1 pn 1
Wilson’s Theorem
If p is a prime, then (p — 1)! = –1 (mod p)
71
Number Theory
Lucas Theorem
In number theory, Lucas’s theorem expresses the remainder of division of the binomial coefficient
mC by a prime number p in terms of base p expansions of integers m and n.
n
Formulation :
k
m m
n
nii (mod p),
i 0
int C[r+1];
memset(C, 0, sizeof(C));
C[0] = 1;
for (int i = 1; i <= n; i++)
{
for (int j = min(i, r); j > 0; j—)
C[j] = (C[j] + C[j-1])%p;
}
return C[r];
}
72
Number Theory
First let’s deal with the base A. Now what we have to find is A%(10 9 + 7). This is beacause, let’s
suppose B = n (where n is an integer). A can be expressed as
73
Number Theory
Hence AB %p A(a (p1) b) %p {[A a (p1) ]%p [Ab ]%p} %p (Ab )%p
Finally
Let x = A %(10 9 + 7), n = B %(10 9 + 7 – 1)
Required answer would be x%(10 9 + 7) which can be found out easily by fast modulo exponentiation
in O(logn).
74
Number Theory
x x2 mod n
if x = 1 then
return composite
if x = n – 1 then
continue W itnessLoop
return composite
return probably prime
Example :
Input: n = 13, k = 2
1. Computed d and r such that d*2r = n – 1,
d = 3, r = 2.
2. Call millerTest k times.
1st Iteration:
1. Pick a random number ‘a’ in range [2, n – 2]
Suppose a = 4
2. Compute: x = pow(a, d) % n
x = 43 % 13 = 12
3. Since x = (n – 1), return prime.
IInd Iteration:
1. Pick a random number ‘a’ in range [2 + n – 2]
Suppose a = 5
2. Compute: x = pow(a, d) % n
x = 53 % 13 = 8
3. x neither 1 nor 12
4. Do following (r – 1) = 1 times
(a) x = (x * x) % 13 = (8 * 8) % 13 = 12 (b) Since x = (n – 1), return true.
Since both iterations return true, we return prime.
POWPOW2, Spoj
Problem :
75
Number Theory
76
Number Theory
After finding y = b (2n, n) mod 1000000006, we can calculate a y mod 1000000007 normally to get the final
result.
Code :
#include<bits/stdc++.h>
#define ll long long int
int t;
ll a, b, n;
ll fact[200005];
ll md = 1000000007;
long long int c_pow(ll i, ll j, ll mod)
{
if (j == 0)
return 1;
ll d;
d = c_pow(i, j / (long long)2, mod);
if (j % 2 == 0)
return (d*d) % mod;
else
return ((d*d) % mod * i) % mod;
}
ll InverseEuler(ll n, ll MOD)
{
return c_pow(n, MOD - 2,MOD);
}
ll fact_14[1700][1700];
ll fact_B[150000];
ll min1(ll a, ll b)
{
return a > b ? b : a;
}
void calc_fact()
{
fact[0] = fact[1] = 1;
ll tmd = 148721;
for (int i = 2; i < 200003; ++i)
{
fact[i] = (fact[i - 1] * i);
if (fact[i] >= (tmd))
77
Number Theory
fact[i] %= (tmd);
}
}
ll fact_41[200005];
ll fact_41_p[200005];
void do_func()
{
fact_41[0] = 1;
fact_41_p[0] = 0;
for (int i = 1; i < 200003; ++i)
{
ll y = i;
fact_41_p[i] = fact_41_p[i - 1];
while (y % 41 == 0)
{
y = y / 41;
fact_41_p[i]++;
}
fact_41[i] = (y*fact_41[i - 1]) % 1681;
}
}
ll fact_2[200005];
void do_func2()
{
fact_2[0] = 1;
for (int i = 1; i < 200005; ++i)
{
fact_2[i] = (i*fact_2[i - 1]) % 2;
}
}
ll get_3rd(ll n, ll r, ll MOD)
{
ll ans = (InverseEuler(fact[r], MOD)*InverseEuler(fact[n - r], MOD)) % MOD;
ans = (fact[n] * ans) % MOD;
return ans;
}
ll inverse2(ll m1, ll p1)
78
Number Theory
{
ll i = 1;
while (1)
{
if ((m1*i) % p1 == 1)
return i;
i++;
}
}
ll chinese_remainder_2(ll n1, ll n2, ll n3)
{
ll p1 = 2, p2 = 1681, p3 = 148721;
ll m1, m2, m3;
ll i1, i2, i3;
ll m;
ll ans;
m = p1*p2*p3;
m1 = m / p1; m2 = m / p2; m3 = m / p3;
i1 = InverseEuler(m1, p1); i2 = inverse2(m2, p2); i3 = InverseEuler(m3, p3);
//printf(“i1 = %lld i2 = %lld\n”,i1,i2);
ans = (n1*m1*i1) % m + (n2*m2*i2) % m + (n3*m3*i3) % m;
ans = ans%m;
return ans;
//printf(“%d\n”,ans);
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
calc_fact();
do_func();
do_func2();
cin >> t;
while (t—)
{
cin >> a >> b >> n;
if (a == 0 && b == 0)
{
79
Number Theory
if (b == 0)
{
cout << “1\n”;
continue;
}
ll a1 = (n == 0) ? 1 : 0;
ll a2 = (fact_41[2 * n] * inverse2(fact_41[n],1681)) % 1681;
a2 = (a2 * inverse2(fact_41[n], 1681)) % 1681;
a2 = (a2 * c_pow(41, fact_41_p[2 * n] - 2 * fact_41_p[n], 1681)) % 1681;
ll a3 = get_3rd(2 * n, n, 148721);
//cout << a1 << “ “ << a2 << “ “ << a3 << “\n”;
ll ans = chinese_remainder_2(a1, a2, a3);
if (ans == 0)ans = 500000002;
ll y1 = c_pow(b, ans, md - 1);
cout << y1 << “\n”;
ll z = c_pow(a, y1, md);
cout << z << “\n”;
}
return 0;
}
#include<iostream>
using namespace std;
#include<vector>
/* This function calculates (a^b)%MOD */
long long pow(int a, int b, int MOD)
{
long long x=1,y=a;
while(b > 0)
{
if(b%2 == 1)
80
Number Theory
{
x=(x*y);
if(x>MOD) x%=MOD;
}
y = (y*y);
if(y>MOD) y%=MOD;
b /= 2;
}
return x;
}
/* Modular Multiplicative Inverse
Using Euler’s Theorem
a^(phi(m)) = 1 (mod m)
a^(-1) = a^(m-2) (mod m) */
long long InverseEuler(int n, int MOD)
{
return pow(n,MOD-2,MOD);
}
long long C(int n, int r, int MOD)
{
vector<long long> f(n + 1,1);
81
Number Theory
Modular Exponentiation :
We can now clearly see that this approach is very inefficient, and we need to come up with something
better. We can take care of this problem in O(log2b) by using a technique called exponentiation by squaring.
This uses only O(log2b) squarings and O(log2b) multiplications. This is a major improvement over the most
naive method.
Code :
ans=1 //Final answer which will be displayed
while(b !=0 ) {
/*Finding the right most digit of ‘b’ in binary form, if it is 1, then multiply
the current value of a
in ans. */
if(b&1) { //rightmost digit of b in binary form is 1.
ans = ans*a ;
ans = ans%c; //at each iteration if value of ans exceeds then
reduce it to modulo c.
}
a = a*a; /
a %= c; //at each iteration if value of a exceeds then reduce
it to modulo c.
b >>= 1; //Trim the right-most digit of b in binary form.
Questions :
1. Find sum of divisors of all the numbers from 1 to n . n <= 10^5.
(SPOJ DIVSUM)
Here n is relatively small so we can precompute all the divisor sum using sieve like approach
which runs in O(NLOGN).
Code :
ll sum[5000005];
void sieve()
{
F(i,1,5000002)
{
for(ll j=i;j<=5000002;j+=i) // every j has i as a divisor
{
sum[j] += i;
82
Number Theory
}
}
// subtract number itself from sum if proper divisors are required
F(i,1,5000002)
sum[i] -= i;
}
83
Number Theory
84
Number Theory
}
ll factorize(ll n) // find multiplication of all (p^(k+1)-1)/(p-1) where k is
the power of p in n
{
// exhaust powers of 2 first
ll c = 0;
while(n%2 == 0)
{
c++;
n = n/2;
}
ll i=0 , ans = 1ll;
if(c>0)
ans = (power(2ll,c+1) - 1);
ll times = 0;
ll p = primes[0];
while(p*p <= n)
{
//times++;
if(n%p == 0) // if p is a prime factor of n
{
ll cnt = 0; // find power of p
while(n%p == 0)
{
//times++;
n /= p;
cnt++;
}
// update ans;
ll numerator = power(p,cnt+1) - 1;
//debug(numerator);
ll denom = p - 1;
ll curans = numerator/denom;
ans = ans * (curans);
}
//debug(n);
if(n == 1)
85
Number Theory
break;
i++;
p = primes[i];
}
//debug(times);
if(n != 1)
ans = ans * (n+1);
return ans;
}
int main()
{
std::ios::sync_with_stdio(false);
sieve();
//cout<<primes.size(); //5761455 primes less than 10^8
ll t;
cin>>t;
while(t—)
{
ll n;
cin>>n;
ll ans = factorize(n);
ans -= n;
cout<<ans<<endl;
}
return 0;
}
86
Number Theory
x1 = a%p1
x2 = a%p2
This is a set of equations satisfying the CRT criteria hence we can calculate the value of a using CRT.
Code :
/*input
5
*/
#include <bits/stdc++.h>
#include<stdio.h>
using namespace std;
#define F(i,a,b) for(ll i = a; i <= b; i++)
#define RF(i,a,b) for(ll i = a; i >= b; i—)
#define pii pair<ll,ll>
#define PI 3.14159265358979323846264338327950288
#define ll long long
#define ff first
#define ss second
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define debug(x) cout << #x << “ = “ << x << endl
#define INF 1000000009
#define mod 109546051211 // 186583*587117
#define S(x) scanf(“%d”,&x)
#define S2(x,y) scanf(“%d%d”,&x,&y)
#define P(x) printf(“%d\n”,x)
#define all(v) v.begin(),v.end()
ll power(ll a,ll b,ll m)
{
ll ans = 1ll;
while(b > 0)
{
if(b&1)
ans = ans*a;
a = a*a;
ans%=m;
a%=m;
87
Number Theory
b /= 2;
}
return ans;
}
int main()
{
std::ios::sync_with_stdio(false);
ll n;
cin>>n;
//use crt since MOD = p1*p2
ll p1 = 186583ll;
ll p2 = 587117ll;
// find first value with respect to p1 and second value with respect to p2
ll ans_p1 = 1ll , ans_p2=1ll , curfactorial_p1 = 1ll , curfactorial_p2 = 1ll;
F(i,2,n)
{
curfactorial_p1 = curfactorial_p1*i;
curfactorial_p1 %= p1;
curfactorial_p2 = curfactorial_p2*i;
curfactorial_p2 %= p2;
ans_p1 = ans_p1*curfactorial_p1;
ans_p1 %= p1;
ans_p2 = ans_p2*curfactorial_p2;
ans_p2 %= p2;
}
//debug(ans_p1);
//debug(ans_p2);
// num[0] = p1 , num[1] = p2
// rem[0] = ans_p1 rem[1] = ans_p2
// pp[0] = p2 pp[1] = p1
// prod = p1*p2
// inv[i] = mpdular multiplicative inverse of pp[i] with respect to num[i]
// inv[0] = inverse of p2 w.r.t p1 , inv[1] = inverse of p1 w.r.t p2
// first remainder is ans_p1 and second remainder is ans_p2
// (x%p1) = ans_p1
// (x%p2) = ans_p2 , we can combine these two to find x
88
Number Theory
// x = rem[0]*inv[0]*pp[0] + rem[1]*inv[1]*pp[1]
ll inv_zero = power(p2,p1-2ll,p1); // fermats
ll inv_first = power(p1,p2-2ll,p2); // fermats
ll ans = (((ans_p1*inv_zero)%mod)*(p2%mod))%mod +
(((ans_p2*inv_first)%mod)*p1%mod)%mod;
ans %= mod;
cout<<ans<<endl;
return 0;
}
TRY YOURSELVES
89
Number Theory
90
Number Theory
91
Number Theory
92