費馬小定理:若p是素數,a是正整數且不能被p整除,則ap-1 == 1(mod p)
費馬小定理的拓展:ap == a(mod p)
歐拉定理:對任意互素的a和n. 設Φ(n) 為小於n且與n互素的正整數的個數,有aΦ(n) == 1(mod n)
歐拉定理的拓展:aΦ(n)+1 == a(mod n)
求乘法逆元的作用:除以一個數 再取模時,可以將這個數乘以這個數的逆元 再取模(將除法轉化成乘法運算)
為什么要這樣等價:對於 (a/b)% mod 這個式子,是不可以等價為 ((a%mod) / (b%mod))%mod 的 (例如:a=3,b=2,mod=3),但是可以寫為(a*b-1)%mod,其中b-1表示b的逆元。這就是逆元的作用
引用計蒜客某題面:
什么是乘法逆元:a*x = 1(mod C),那么稱 x 為 a 對 C 的乘法逆元
e.g. a = 4,C = 7 則逆元 x = 2;
4*2=1(mod 7) 12/4%7 = (12*2)%7 (除法換乘法)
用一道入門題來來學習三中模板:https://www.luogu.org/problem/P3811
模板一:
線性打表遞推法:(遞推公式:inv[i] = (p-p/i) * inv[p%i] % p )
這種方法最快,但是耗費的空間多
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <ctime> 6 #include <climits> 7 #include <utility> 8 #include <deque> 9 #include <queue> 10 #include <map> 11 #include <algorithm> 12 #include <functional> 13 using namespace std; 14 typedef long long ll; 15 16 ll inv[3000006]; 17 int main() 18 { 19 ll a, p; 20 while(~scanf("%lld %lld", &a, &p) ) 21 { 22 memset(inv, 0, sizeof(inv)); 23 inv[0] = 1; 24 inv[1] = 1; 25 for(ll i=2; i<=a; i++ ) 26 inv[i] = (p-p/i)*inv[p%i]%p; 27 for(ll i=1; i<=a; i++ ) 28 printf("%lld\n", inv[i]); 29 } 30 return 0; 31 }
模板二:
拓展歐幾里得算法
這道題我用這個方法TLE了,這個次慢
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <ctime> 6 #include <climits> 7 #include <utility> 8 #include <deque> 9 #include <queue> 10 #include <map> 11 #include <algorithm> 12 #include <functional> 13 using namespace std; 14 typedef long long ll; 15 16 void exgcd(ll a, ll b, ll &x, ll &y) 17 { 18 if( b==0 ) 19 { 20 x=1; 21 y=0; 22 return ; 23 } 24 exgcd(b, a%b, y, x); 25 y -= (a/b)*x; 26 return ; 27 } 28 29 int main() 30 { 31 ll a, p; 32 ll x, y; 33 while( ~ scanf("%lld %lld", &a, &p) ) 34 { 35 for(ll i=1; i<=a; i++ ) 36 { 37 exgcd(i, p, x, y); 38 x = (x%p+p)%p; 39 printf("%lld\n", x); 40 } 41 } 42 return 0; 43 }
模板三:
費馬小定理算法:(快速冪(a,p-2,p)),前提是a p互質,這個也TLE了,這個最慢
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <ctime> 6 #include <climits> 7 #include <utility> 8 #include <deque> 9 #include <queue> 10 #include <map> 11 #include <algorithm> 12 #include <functional> 13 using namespace std; 14 typedef long long ll; 15 16 ll fpm(ll x, ll power, ll mod) 17 { 18 ll ans = 1; 19 for( ; power; power>>=1,(x*=x)%=mod ) 20 if( power&1 ) 21 (ans*=x)%=mod; 22 return ans; 23 } 24 25 int main() 26 { 27 ll a, p; 28 ll x, y; 29 while( ~ scanf("%lld %lld", &a, &p) ) 30 { 31 for(ll i=1; i<=a; i++ ) 32 { 33 printf("%lld\n", fpm(i,p-2,p)); 34 } 35 } 36 return 0; 37 }