Skip to main content

Number theory Pt II

The Return of Number Theory 

We covered in the First part:

  1. Primarily Test
  2. Prime Factorisation
  3. Sieve of Eratosthenes
  4. Binary Exponentiation
  5. Euclid's Algorithm for GCD
  6. Number of divisors/sum of divisors
  7. Segmented Sieve
We would cover:
  1. Modulus Operations
  2. Binomial Coefficients
  3. Extended Euclidian Algorithm
  4. Diophantine
  5. Matrix Exponentiation
  6. Fibonacci in O(log(n))
  7. Chinese Remainder Theorem
  8. Euler's Totient Function
And these are the methods which we would cover only in theory, no questions in the fight:
  1. Pollard p-1
  2. Pollard rho algorithm

Modulus Arithmetic:

Before jumping to the formulas for addition, subtraction, etc., firstly, let's have a look at what is Modular Congruence.

Modular Congruences:

a and b are modular congruent under n if they give the same remainder on dividing by n.
Representation: a b(mod n) 
What that means is that wherever you are given a%n, you can replace it with b%n and it would have no impact no final answer, for example, 
9=13 mod 4
(12+9)%4=21%4=1
(12+13)%4=25%4=1

With this, there is a great observation, we just made: a%n (remainder when a is divided by n) is always congruent to a under n! i.e.: aa%n(mod n).
Now, let's suppose, I ask you to compute (a*b)%n, which is quite simple, but if a and b are greater than 10^9, you can't store a*b in a long long int, so, we can safely replace a with a%n and b with b%n to get:
(a*b)%n=((a%n)*(b%n))%n
This is an essential property commonly used in many theorems; similarly, you can do the same in addition as well:
(a+b)%n=(a%n+b%n)%n

But when it comes to division, there is a different story. 
But before moving to that, let's see a trick:

Finding the last digit of some big number*another big number:
123456*7890123
So, let's be clear on what exactly we want to find:
(a*b)%10 (last digit)
Now, things are already sorted: (a*b)%n=(a%n*b%n)%n
=(123456%10*7890123%10)%10=(6+3)%10=9

For seeing the proof of divisibility rule of 9 and 3 using modular arithmetic, click here.

Also, a-b≡0 mod n, I.e. a-b is divisible by n.

Modular Exponentiation:

If a≡b mod N. then
a^k≡b^k mod N

Again, using the observation that a=a%n mod N
(a^k)%n=((a%n)^k)%n 
for eg, let's calculate (25^20)%12=((25%12)^20)%12=(1^20)%12=1

But wait, we can have something like (2^123456789)%7 also.
If you did It by the same approach, come on man, why would I make you do the same thing again, this time, you just replace 2 by 8 and divide 123456789 by 3. And 8%7=1. So whatever be the power, the answer is going to be one.

Simple enough?
Let's now jump to Modular inverse, the rules in division operation in modulus arithmetic:

Modulo Multiplicative Inverse

We can't just use (a/b)%c != (a%c/b%c)%c
But what we can do, is just replace / by *: (a*(1/b))%c
=(a%c*((1/b)%c))%c

What we need to find is now (1/b)%c

So, modulo multiplicative inverse of a number b under N is said to be x, if:
b*x≡1 mod p

And it can be a case where modulo inverse doesn't exist. If b and p are coprime to each other, then only modulo inverse exists. (GCD(b,p)=1)

So, how do we find modulo inverse?

Fermat's Little Theorem:

Fermat's little theorem states this equation:
am-1=1 mod m
am-2= a-1 mod m
So, calculate a^m-2, and a^m-2 is the modulo inverse of a.
Caution: use binary exponentiation to calculate a^m-2, else you would get the time complexity as O(sqrt(n)).

Binomial Coefficients using Modulo Inverse:

Given q queries of type n k, you have to calculate C(n,k)%P, where p>n.(mostly p=10^9 + 7)
We know that,
C(n, k)= n!/[k!(n-k)!]
and C(n,k)%p=(n!%p)/[(k!%p)*((n-k)!%p)]

Precalculate factorial in an array of size 10^6. And inverse modulo k! and (n-k)!. For inverse modulo, use binary exponentiation. See code here.

Extended Euclidean Algorithm

Concept:

Examples:

Questions:

...................................

Diophantine

Concept:

Examples:

Questions:

...................................

Matrix Exponentiation

Concept:

Examples:

Questions:

...................................

Fibbonacci in O(log(n))

Concept:

Examples:

Questions:

...................................

Chinese Remainder Algorithm

Concept:

Examples:

Questions:

...................................

Euler's Totient Function

Concept:

So, what's this fancy term actually mean?
This function returns the number of positive integers up to n which are coprime to n.
Fascinating, huh?
The naive solution is straightforward, and it's just a for loop up to n, and taking GCD of each i with n, a simple approach, time complexity: O(nlog(n))
Let's see in detail how this works:
Let F(n) be our Euler totient function.
Now there are these cases:
1. Case 1: If n is a prime number => If n is a prime number, the answer is just n-1. I don't think I have to explain that too. But still, a prime number is a number that has gcd equal to 1 with all numbers except for itself.
2. Case 2: If n is of the form P^x where P is a prime number. This is a bit tricky but still simple. 
F(n)=P^x- number of integers not coprime with P^x.
And the numbers which are not coprime are those which are divisible by P. Eg, in 3^5, the number of integers divisible by 3 till 3^5, are 3^4=81. and 3^5=243. 
Ans= 243-81+1=162.(+1 for 3^5 itself)
So, F(n)=P^x-P^(x-1)=(P^(x-1))*(P-1)

General Formula:
So, here is an interesting property of Euler's totient function: it is multiplicative. What that means is:
f(n*m)=f(n)*f(m)
So, your brain must be predicting what would happen next: we split N into its prime factorization form and just calculate the result! Every number is of the form Px1*Px3*Px3
So, F(n)=F(p1^x1)*F(p2^x2)*....
=(P1^(x1-1))*(P1-1)*(P2^(x2-1))*(P2-1)....
But to calculate the prime factorization, you would take O(sqrt(n)) and calculate exponents, O(log(n)). And iterating through would take time O(number of prime divisors). So, you can transform the same formula to a much cleaner formula: 
N*((P1-1)/p1)*((p2-1)/p2)*..... 
So, just iterating through the prime factors, make time complexity: O(sqrt(n)).
Full Code Implementation:
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n;
	cin>>n;
	int ans=n;
	for(int i=2;i<=sqrt(n);i++)
	{
		if(!(n%i))
		{
			ans*=(i-1);
			ans/=i;
			while(!(n%i))
				n/=i;
		}
	}	
	if(n>1)
	{
		ans*=(n-1);
		ans/=n;
	}
	cout<<"F(n): "<<ans<<"\n";
	return 0;
}

Examples:

Questions:

...................................

Comments

Popular posts from this blog

Competitive Prograaming From 1000 rating to 2400+

Okay, so let's talk about some strategies for competitive programming. I was once a gray coder as I was totally new to programming when I entered codeforces. FROM GRAY TO GREEN:     First of all, you need to be good at brute force and implementation. If you are a complete beginner then do 20-30 800-1200 problems and you will b good at solving A level problems in 5-10 minutes. The try to do B in a live contest in 15-30 minutes only. By only this you can shift your rating to 1200 or so. FROM GREEN TO CYAN Now, to increase your speed you just need to practice more A and B level problems. As you are now quite confident of solving A and B level problems you must now try C also which is generally of 1400-1700 rating. This require some special techniques such as prefix sum, or some simple trick methods for reducing time complexity. Now the mistake I did was I tried to learn more advanced data structures such as graphs, trees, KMP algorithm, etc and that wasn't ne...