Number Theory #2

By Sadek Mohammed

Modular Arithmetic

We have investigated modulus (%) as a way to get the remainder after divison, but what does modulus do?

Clock Model

The easiest way to imagine the workflow of the modulus is to imagine the clock. A clock has 12 hours, where certain hours repeat. To illustrate:

What can we get from that.

Imagine that you have a rotated number line, where it has the following marks: . Look at the following:

We can conclude that multiples of the modulus cause complete cycles around the number line. That means they could be eliminated when calculating the modulus.

, but how to define that correspondence in a precise way?

Division model

Any two integers and could be put in the following formula.

Some Facts:

When there is no remainder, a number could be expressed in terms of as the following . We can proof that numbers which are divisble by a third number have a difference that is divisble by that number, too.

The same holds for addition, too, by a similar proof.

Some terms:

Congurence:

Two integers are said to be congruent (mod x) if they have the same remainder () when divided by x. For example:

Range of a modulus

Distribution

On solving some problems, the problem statement sometimes requires that you output the answer mod a certain number as the number may get too big. For example, take the following:

Problem Statement

A certain person has a number of categories of clothes (), where each category has pieces (). You have to output the number of different combinations of clothes. (Since the number of combinations could be huge, output it )

Sample Input

3 3 2 1

Sample Output

6

Explanation of Sample

The person has 3 categories: shoes, trousers, and shirts. He has 3 shoes, 2 trousers, and a single shirt. That means that the total number of possibilities is .

How to solve ?

Look at the following code:

// Initialize the vairables (Notice that ans starts with 1)
int ans = 1, n = 0, inp = 0;
// Take the number of clothes categories
cin >> n;
while (n--)
{
    // Take the number of pieces of each category
     cin >> inp;
    // Multiply them by the answer (1)
    ans *= inp;
}
// Output the answer
cout << ans;

But there is a single problem. We need to ouptut the number . In our case, the numbers are too big. Let's do some maths.

Fortunately, the problem statement is the supreme savior. If we take the answer repeatedly , we would always obtain an answer that is always less than that perfectly fits in a normal -bit integer. To do so we need to have some knowledge about the distribution of operations.

Distribution Rules

Proof of distributive addition rule:

You can look for proofs for subtraction and multiplication, too.

New code

int n = 0;
// Notice that both ans and inp became long long 
long long ans = 1, inp = 0;
// Note that ans is initialized by 1 (Multiplicative Identity)
cin >> n;
while (n--)
{
    cin >> inp;
    // Take inp mod 
    inp %= mod; 
    ans *= inp;
    // Take ans mod
    ans %= mod; 
}
cout << ans;

Notice the following:

Modulus of negative numbers

Taking modulus of negative numbers differs according to the language; however, in cpp, we do the following:

int all_mod (int n, int m)
{
    return ((n % m) + m) % m;
}

This method works for positive numbers, too. That's because all we do is neglecting the multiples of the modulus as in the clock model.

The greatest common divisor.

What is the gcd.

Imagine the following numbers:

In the previous session, we have observed that 12 must have 6 divisors: . On the contrary, 8 must have 4 divisors: .

We could observe that they have 3 common divisors: . The greatest commond divisor (gcd) is .

How could I find the gcd of two numbers?

Let a be a number with prime divisors: and b be a number with the following divisors: . Let their gcd be c.

How to do that on a computer?

Euclidean Theorem.

Since each number that divides and divides their difference . We can find the gcd this way:

Extended Euclidean Theorem.

If you could remember the clock model, we were extensively subtracting 12s from the hour to get its counterpart in the range . The same goes with a great improvement to the euclidean theorem.

Code

The extended euclidean algorithm can be implemented as follows:

int gcd(int a, int b)
{
    if (a < b)
    {
        swap(a, b);
    }
    if (b == 0)
    {
        return 0;
    }
    return gcd(b, a%b);
}

The least common multiple.

What is the lcm?

See the following:

There can be common multipes: 70, 140, etc; however, the least one of them is .

But how could that happen?

Observe the following:

How could I find the gcd of two numbers?

Let a be a number with prime divisors: and b be a number with the following divisors: . Let their gcd be c.

How to do that on a computer?

When we take the gcd for two numbers like 42 and 28 .

Their GCD & LCM

Let's look at the exponents of the prime factors:

This implies that:

Let's look at the following:

It can be concluded that result of multiplying the two numbers has all their factors, GCD has the minimum factors only, and LCM has the maximum factors, so if we can find the GCD and a way to remove the minimum factors, we could find the maximum factors, lcm.

When using this with the above way of calculating the gcd, the process becomes very efficient.