Reciprocal number theory, also known as inverse element (because I said I am used to inverse element, I will say inverse element below)
The reciprocal in number theory has a special meaning.
Do you think the reciprocal of a is still 1/a in number theory?
(・∀・) hum ~ naive
Let's first introduce the concept of remainder
(a + b) % p = (a%p + b%p) %p (pair)
(a - b) % p = (a%p - b%p) %p (pair)
(a * b) % p = (a%p * b%p) %p (pair)
(a / b) % p = (a%p / b%p) %p (wrong)
why division is wrong
It's hard to prove right, just give a counter example to prove wrong
(100/50)%20 = 2 ≠ (100%20) / (50%20) %20 = 0
For some problems, we must calculate the remainder in the middle process, otherwise the number is too large for the computer to store. If there is a division in this formula, can we not calculate this formula?
The answer is of course NO (>o<)
Then you need the inverse
we know
if
a*x = 1
Then x is the reciprocal of a, x = 1/a
But if a is not 1, then x is a decimal
In that number theory, most cases have a remainder, so now the problem has changed
a*x = 1 (mod p)
So x must be equal to 1/a
uncertain
So at this time, we regard x as the reciprocal of a, but add a remainder condition, so x is called the inverse of a with respect to p
For example, 2 * 3 % 5 = 1, then 3 is the inverse of 2 to 5, or that 2 and 3 are inverses of 5 to each other
Is the effect of 3 the same as the effect of 1/2, so it is called the reciprocal of number theory
The inverse of a, we use inv(a) to denote
Then (a / b) % p = (a * inv(b) ) % p = (a % p * inv(b) % p) % p
This completely converts division into multiplication (.・ω・), and multiplication is super easy
The main story begins
How to find the inverse element
(Forgot to say that a and p are relatively prime, so a has an inverse element about p)
method one:
Fermat once said: A mathematician who doesn’t want to be a mathematician is not a good mathematician (( ̄▽ ̄)~*What I said casually, don’t take it seriously)
Fermat's little theorem
a^(p-1) ≡1 (mod p)
Divide both sides by a
a^(p-2) ≡1/a (mod p)
What (,,• ₃ •,,), this is number theory, dare to write 1/a
should write a^(p-2) ≡ inv(a) (mod p)
So inv(a) = a^(p-2) (mod p)
Find this with a quick exponentiation, the complexity is O(logn)(ง •̀_•́)ง
1 LL pow_mod(LL a, LL b, LL p){//a的b次方求余p 2 LL ret = 1; 3 while(b){ 4 if(b & 1) ret = (ret * a) % p; 5 a = (a * a) % p; 6 b >>= 1; 7 } 8 return right; 9 } 10 LL Fermat(LL a, LL p){//Fermat finds the inverse of a about b 11 return pow_mod(a, p-2, p); 12 }
Method Two:
To use the extended Euclidean algorithm
Remember Extended Euclid? (If you don’t remember, Euclid will be sad (╭ ̄3 ̄)╭♡)
a*x + b*y = 1
If ab is coprime, there is a solution
The x of this solution is the inverse of a with respect to b
y is the inverse of b with respect to a
why?
You see, both sides find the remainder b at the same time
a*x % b + b*y % b = 1 % b
a*x % b = 1 % b
a*x = 1 (mod b)
Look, look, it appears! ! ! (/≥▽≤/)
So x is the inverse of a with respect to b
Conversely, it can be proved that y
Attached code:
1 #include<cstdio> 2 typedef long long LL; 3 void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){ 4 if (!b) {d = a, x = 1, y = 0;} 5 else{ 6 ex_gcd(b, a % b, y, x, d); 7 and -= x * (a / b); 8 } 9 } 10 LL inv(LL t, LL p){//If it does not exist, return -1 11 LL d, x, y; 12 ex_gcd(t, p, x, y, d); 13 return d == 1 ? (x % p + p) % p : -1; 14 } 15 int main(){ 16 LL a, p; 17 while(~scanf("%lld%lld", &a, &p)){ 18 printf("%lld\n", inv(a, p)); 19 } 20 }
Method three:
When p is prime we have
inv(a) = (p - p / a) * inv(p % a) % p
Why is this right?
Prove that kids who don't want to watch can skip it. . . ( ̄0 ̄)
Proof:
Let x = p % a, y = p / a
then x + y * a = p
(x + y * a) % p = 0
shift the term to get x % p = (-y) * a % p
x * inv(a) % p = (-y) % p
inv(a) = (p - y) * inv(x) % p
so inv(a) = (p - p / a) * inv(p % a ) %p
Then recurse until 1, because the inverse of 1 is 1
Code:
1 #include<cstdio> 2 typedef long long LL; 3 LL inv(LL t, LL p) {//Seek the inverse of t with respect to p, note: t should be less than p, it is best to pass t%p before passing parameters 4 return t == 1 ? 1 : (p - p / t) * inv(p % t, p) % p; 5 } 6 int main(){ 7 LL a, p; 8 while(~scanf("%lld%lld", &a, &p)){ 9 printf("%lld\n", inv(a%p, p)); 10 } 11 }
This method is not limited to finding a single inverse, it is better than the first two, it can calculate the inverse of n numbers within O(n) complexity
Recursion is the above way of writing, add a memory recursion, you can
Recursive write like this
1 #include<cstdio> 2 const int N = 200000 + 5; 3 const int MOD = (int)1e9 + 7; 4 int inv[N]; 5 int init(){ 6 inv[1] = 1; 7 for(int i = 2; i < N; i ++){ 8 inv [i] = (MOD - MOD / i) * 1ll * inv [MOD% i]% MOD; 9 } 10 } 11 int main(){ 12 init(); 13 }
Reprinted from:
https://www.cnblogs.com/linyujun/p/5194184.html