PrevNext
Not Frequent
 0/3

Modular Arithmetic

Authors: Darren Yao, Michael Cao, Andi Qu, Benjamin Qi, Andrew Wang

Prerequisites

Working with remainders from division.

Resources
IUSACOvery brief, module is based off this
David Altizioplenty of examples from math contests
CPH
PAPS
CFsome practice probs

Introduction

In modular arithmetic, instead of working with integers themselves, we work with their remainders when divided by . We call this taking modulo . For example, if we take , then instead of working with , we use . Usually, will be a large prime, given in the problem; the two most common values are and . Modular arithmetic is used to avoid dealing with numbers that overflow built-in data types, because we can take remainders, according to the following formulas:

Modular Exponentiation

Focus Problem – read through this problem before continuing!

Resources

Resources
cp-algo

Binary exponentiation can be used to efficently compute . To do this, let's break down into binary components. For example, = = . Then, if we know for all which are powers of two (, , , , , we can compute in .

To deal with , observe that modulo doesn't affect multiplications, so we can directly implement the above "binary exponentiation" algorithm while adding a line to take results .

Solution - Exponentiation

Solution

Modular Inverse

The modular inverse is the equivalent of the reciprocal in real-number arithmetic; to divide by , multiply by the modular inverse of . We'll only consider prime moduli here.

For example, the inverse of modulo is . This means that for any integer ,

For example, .

Resources
cp-algoVarious ways to take modular inverse, we'll only discuss the second here

With Exponentiation

Fermat's Little Theorem (not to be confused with Fermat's Last Theorem) states that all integers not divisible by satisfy . Consequently, . Therefore, is a modular inverse of modulo .

C++

1int main() {
2 ll m = 1e9+7;
3 ll x = binpow(2,m-2,m);
4 cout << x << "\n"; // 500000004
5 assert(2*x%m == 1);
6}

Java

1public class main
2{
3 public static void main(String[] args) throws IOException
4 {
5 long m = (long)1e9+7;
6 long x = binpow(2,m-2,m);
7 System.out.println(x); // 500000004
8 assert(2*x%m == 1);
9 }
10}

Because it takes time to compute a modular inverse modulo , frequent use of division inside a loop can significantly increase the running time of a program. If the modular inverse of the same number(s) is/are being used many times, it is a good idea to precalculate it.

Also, one must always ensure that they do not attempt to divide by 0. Be aware that after applying modulo, a nonzero number can become zero, so be very careful when dividing by non-constant values.

Optional: Another Way to Compute Modular Inverses

We can also use the extended Euclidean algorithm. See the module in the Advanced section.

Templates

Resources
Benq
Benqfeasible to type up during a contest

Using my template, both of these do the same thing:

1int main() {
2 {
3 int a = 1e8, b = 1e8, c = 1e8;
4 cout << (ll)a*b%MOD*c%MOD << "\n"; // 49000000
5 }
6 {
7 mi a = 1e8, b = 1e8, c = 1e8;
8 // cout << a*b*c << "\n"; // doesn't work
9 // ^ not silently converted to int
10 cout << int(a*b*c) << "\n"; // 49000000

Problems

StatusSourceProblem NameDifficultyTagsSolutionURL
CSESEasy
Show Tags

modular arithmetic

View Solution
CFEasy
Show Tags

modular arithmetic

Check CF

Module Progress:

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!

Give Us Feedback on Modular Arithmetic!

PrevNext