math problems francis fok 9 th oct. content greatest common divisor prime number algorithm find...
TRANSCRIPT
Greatest common divisor
DefinitionDivisibility : a | b if there exists an integer x, such that a * x = b
We call a is divisor of b.
Definition
Common divisor : c is divisor of both x and y if c | x and c | y.
Greatest Common divisor: d = gcd(x,y) = Max { c | c is common divisor of
x,y)
Properties
gcd(x,y) ≥ 0 gcd(x,0) = x for x != 0 gcd(x,1) = 1 if y | x , then gcd(x,y) = y if x ≥ y > 0, then gcd(x,y) = gcd(y,x mod y) (it is known as “Euclidean algorithm”)
gcd (Recursive style)
int gcd(int x, int y){ if(x % y == 0) return y; return gcd(y, x % y);}
Assume x > 0 and y > 0 here“%” means “mod”
gcd (Iterative style)int gcd(int x,int y){ while(x % y != 0){ int t=x; x=y; y=t % y; } return y;}
Assume x > 0 and y > 0 here
lcm (least common multiple)
Lemma :If x , y ≥ 0,then x * y = gcd(x,y) * lcm(x,y)
(Algorithm)int lcm(int x, int y){ return(abs(x) * abs(y) / gcd(x,y));}
Extended Euclidean algorithm
Problem definitionGiven a pair integer x, y (all are
positive)Find a pair of integer a,b such that ax+by=gcd(x,y)
Extended Euclidean algorithmint gcd(int x, int y, int &a, int &b){ if(x mod y == 0){ a=0; b=1; return y; } int temp=a; a=b; b=temp – b * (temp div b); return gcd(y, x % y);}
Prime numberDefinition: (General accepted)Prime number = { x | x have only 2 distinct positive divisor}
Composite number = { x | x>1 and x is not prime}
Normally, 1 is neither prime nor composite.
Sometime , 1 will consider as a prime or a composite
or both.
Example
2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
Example
2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
Example
2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
Example
2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
Example
2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
Find Prime (Version 1)find_prime_1(int x){ array prime; //(may use vector) for(i=2 to x){ bool p=1; for(j = all index in prime) if(i%prime[j]==0) p=0; if(p) insert i into prime }}
Algorithm (Version 1)
Adv : Simple idea and simple coding space efficientDis : Time inefficient
Can we replace the “division” by “addition” and “mutliplication” only?
Find Prime (Version 2a)
find_prime_2a(int x){ bool array prime[x]; initial all prime[i]=1; prime[0]=0; prime[1]=0; for(i = 2 to x) if(prime[i]) for(int j=i*i; j<=x; j+=i) prime[j]=0;}
Find Prime (Version 2b)find_prime_2b(int x){ bool array prime[x]; initial all prime[i]=1; prime[0]=0; prime[1]=0; prime[all even except 2] = 0; for(i = 3 ; i<=sqrt(x); i+=2){ if(prime[i]) for(int j=i*i; j<=x; j+=i) prime[j]=0;}
Find Prime (Version 2b)
Adv : time efficientDis : Only return “Yes” or “No”.
Can we get the divisor from the algorithm?
Find Prime (Version 3)find_prime_3(int x){ int array prime[x]; initial all prime[i]=i; prime[0]=0; prime[1]=0; prime[all even except 2] = 2; for(i = 3 ; i<=sqrt(x); i+=2){ if(prime[i]==i) for(int j=i*i; j<=x; j+=i) if(prime[j] = j) prime[j]=i;}
Example
2 3 2 5 6 7 8 9 10
11 12 13 2 15 16 17 18 19 20
21 22 23 2 25 26 27 28 29 30
31 32 33 2 35 36 37 38 39 40
41 42 43 2 45 46 47 48 49 50
51 52 53 2 55 56 57 58 59 60
61 62 63 2 65 66 67 68 69 70
71 72 73 2 75 76 77 78 79 80
81 82 83 2 85 86 87 88 89 90
Example
2 3 2 5 2 7 2 3 2
11 2 13 2 3 2 17 2 19 2
3 2 23 2 5 2 3 2 29 2
31 2 3 2 5 2 37 2 3 2
41 2 43 2 3 2 47 2 7 2
3 2 53 2 5 2 3 2 59 2
61 2 3 2 5 2 67 2 3 2
71 2 73 2 3 2 77 2 79 2
3 2 83 2 5 2 3 2 89 2
Number theory
Definition:Relative prime x and y are relative prime iff
gcd(x,y)=1
R(x) = { y | y<x and gcd(x,y)=1}Φ(x) = | R(x) |
Formula
Φ(x) = x * product (1-1/p) where p is prime factor of x
Example : Φ(6) = 6 * (1-1/2) * (1-1/3) = 2 Φ(24) = 24 * (1-1/2) * (1-1/3) = 8
phi
phi(int x){ int sol=x,temp; while(x!=1){ temp=prime[x]; y=y*(temp-1)/temp; while(prime[x]==temp) x/=prime[x];} return sol;}
Find Power
Problem: How to find 2^n?
Algorithm(Version 1)find_power(int x){ if(x==1) return(2); return(2 * find(power(x-1));}Problem : time inefficient (linear time)What happen if we call
find_power(100000000)?
Find Power
How we get 2^100000000 by hand?(It is a DP approach)
2^1=2 2^2=4 2^4=16 2^8=256……Find the binary representation of
100000000 and multiplying with corresponding power.
Find Power (Version 2)
find_power(int x){ if(x==1) return(2) y = power(x/2) if(x mod 2==1) return(2 * y * y) else return(y * y)}
Find Power (Version 2)
Adv : sub-linear time can be improved to do any
base rather than 2
Even more powerful, the base can be a matrix.
Example8
10
11
10
11
10
111
10
21
10
11
10
11
10
112
10
41
10
21
10
21
10
114
10
81
10
41
10
41
10
118
Find
Fibonacci number
It seem nothing special using a matrix as base.
Question : Can we find the 1024th Fibonacci number in only 10 steps?
(suppose no overflowing problem)
Fibonacci number
Refer to Bryan’s presentation :Definition of Fibonacci number
f(0) = 0 f(1) = 1 f(n) = f(n – 1) + f(n – 2),
it requires 1024 steps to do.How we can only use 10 steps?
Fibonacci number
We can construct a matrix representing the recurrence relation.
Then, we can find the solution by
n
n
n
n
x
x
x
x 1
101
11
1024
1025
1024
0
1
01
11
x
x
Sum of root power
Suppose p,q are non-zero roots of x2 + bx + c = 0 where b,c are integers.
Then, how to find pn + qn for some positive integer n?
Sum of root power
Direct method :Find p and q by using the quadratic
formula and power the value up to n.
What is the problem?
Sum of root power
Define F(n) = pn + qn .
Then, F(n) = pn + qn
= (pn-1 + qn-1)(p+q) – (pn-2 + qn-2) pq= S F(n-1) – P F(n-2)
So,
n
n
n
n
F
F
F
FPS 1
101
Recurrence relation
In fact, we can model any recurrence relation by a matrix. And find the nth term in sub-linear time.
Improvement
If the base is a matrix , 1) Using iterative style is better
because of memory consideration.
2) Applying Jordan decomposition , we can do the multiplication even more faster. But the drawback is the decomposition is very hard.
Other forms of integer
The type “int”, “unsinged int”, “long long” have a range.
int [- 2^31 , 2^31-1]
unsigned int [ 0 , 2^32-1]
long long [- 2^63 , 2^63-1]
unsigned long long
[ 0 , 2^64-1]
Big integer
What happen if we want to store a num “12345678901234567890”?
We can use a vector to store the number.
Thus, v[0]=0, v[1]=9, v[2]=8……(Remember the order is reverse)
Make the Big Int
Make(string x){ vector<int> number; for(int i=x.size()-1; i>=0; --i) number.push_back(x[i]-’0’);}
Big Int
We need to write the addition , subtraction ,multiplicaton and division ourselves.
How to do addition?
AdditionAddition (vector<int> v, vector<int> u){ vector<int> sol; if(v.size()>u.size()){ sol=v; for(int i=0; i<u.size(); ++i) sol[i]+=u[i]; } else{ sol=u; for(int i=0; i<u.size(); ++i) sol[i]+=u[i]; } for(int i=0; i<sol.size()-1; ++i) if(sol[i]>9){ sol[i+1]+=1; sol[i]=10-sol[i]; } if(sol.back()>9){ sol.push_back(1); sol[sol.size()-2] = 10 - sol[sol.size()-2]; }}
Big Int
We can write the subtraction in the same way.
For multiplication, there are two cases,
Big-Int * Int and Big-Int * Big-Int.
MultiplicationMultiplication (vector<int> v, int u){ vector<int> sol; if(v.size()>u.size()){ sol=v; for(int i=0; i<u.size(); ++i) sol[i]*=u; } for(int i=0; i<sol.size()-1; ++i) if(sol[i]>9){ sol[i+1]+=sol[i]/10; sol[i]=sol[i] mod 10; } while(sol.back()>9){ sol.push_back(1); sol[sol.size()-2] = 10 - sol[sol.size()-2]; }}
Variation
Use string to store the big int For every cell in vector, represent
2 or more digit. (Be care the overflowing problem)
Use Double as integer
Lemma :Any real number can be represented
as Mantissa * 10^Exponentwhere 0≤Mantissa <1And Exponent is an integer
Use Double as integer
Question :How to find the last 4 digits of 2^1000?How to find the first 4 digits of 2^1000?How to find the number of digits of
2^1000?
Of course, we can use Big-int to do.But we can do it faster.
Find last 4 digits
Using the find_power and “mod”.
find_last(int x){ if(x==1) return(2) y = power(x/2) mod 10000 if(x mod 2==1) return(2 * y * y) mod 10000 else return(y * y) mod 10000}
Find first 4 digits
Use mantissa to record the solution.
find_first(int x){ mantissa=0.2; for(int i=1 to x){ mantissa *=2; if(mantissa >=1) mantissa /=10; }}
Becare :The answer = int(mantissa*10000)
Find the number of digits
Use the exponent to record the solution.find_first(int x){ mantissa=0.2; expontent = 0; for(int i=1 to x){ mantissa *=2; if(mantissa >=1) mantissa /=10; ++expontent; }}
Becare :The answer = expontent + 1
Find the number of digits
There is another way to find the number of digit by using “log”.
Number of digit = int(log 2^1000) + 1
= int(1000 log 2) + 1
Use Double as integer
Using Double is taking a risk because of precision consideration.
By the concept of numerical analysis, we can use double if we can control the error. Otherwise, using another method to do so.
Simple counting
Combination and Permutation
Use int or long long may suffer from overflow
Use double may suffer from precision