數論之費馬小定理
費馬小定理:
假如p是素數,且(a,p)=1,那麼a^(p-1)≡1(mod p)
ps:a≡b(modm)表示a,b對模m的餘數相同,如3三5(mod2)等
證明略
注意:
1、費馬小定理只能在 gcd(a,p)=1 條件成立時使用
2、費馬定理是,已知素數p,得到 。但是已知 並不能確定p是素數。
費馬小定理在acm中的應用:
① 判斷素數,對於大素數的判定,Miller-Rabin 素數判定
②求解逆元 ,設a模p的逆元為x,則a*x≡1(mod p) ,(a,p)=1;由費馬小定理可以知道x=a^(p-2)
③對於計算a^b(modp) a^b(modp) 可簡化
對於素數p,任取跟他互素的數a,有a^(p-1)(mod p)=1
所以任取b,有a^b%p=a^(b%(p-1))(%p)從而簡化運算。
①、判斷素數模板(利用(a^p-1)%p是否等於1 來判斷 是不是素數)
#include <iostream> #include <cstring> #include <string> #include <algorithm> #include <cstdio> #include <ctime> #include <cmath> using namespace std; #define ll long long //求a^p%mod ll quick_pow(ll a,ll p,ll mod) { ll ans=1; a=a%mod; while(p) { if(p&1) ans=ans*a%mod; a=a*a%mod; p>>=1; }return ans; } /* 測試 n 是否為素數 s 為 測試次數 (一般為4次) 是素數 返回 1 不是素數 返回 0 */ int Miller_Rabbin(ll n,int s) { ll a; srand(time(NULL)); for(int i=1;i<=s;i++) { a=1+rand()%(n-1); if(quick_pow(a,n-1,n)!=1) return 0; }return 1; } int main() { ll n; while(cin>>n)//"n=1 的時候特判一下" { if(n==1) cout<<" 不是素數"<<endl; else if(Miller_Rabbin(n,4)) cout<<" 是素數"<<endl; else cout<<" 不是素數"<<endl; }return 0; } /* 1 不是素數 23 是素數 2 是素數 3 是素數 4 不是素數 5 是素數 6 不是素數 */
②求解逆元
逆元類似導數的性質 (為什麼不是相等呢?搞不懂 (╥╯^╰╥) 迷之數論)
接下來引入求餘概念
(a + b) % p = (a%p + b%p) %p (對)
(a - b) % p = (a%p - b%p) %p (對)
(a * b) % p = (a%p * b%p) %p (對)
(a / b) % p = (a%p / b%p) %p (錯)--> 除法是不能直接取模的哦 反例:(100/50)%20 = 2 ≠ (100%20) / (50%20) %20 = 0
所以就要藉助逆元了,來把除法轉化成乘法;
a的逆元,我們用inv(a)來表示
那麼-------------------->>>
(a / b) % p = (a * inv(b) ) % p = (a % p * inv(b) % p) % p ( p 是質數且 gcd(a, p) = 1,a才有關於p的逆元)
利用費馬小定理:a^(p-1)≡1(mod p) --> a^(p-2)≡1/a(mod p) --> a^(p-2)≡ inv(a) (mod p);
所以 : inv(a)= a^(p-2)(mod p) ;
利用快速冪求,
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdio>
#include <ctime>
#include <cmath>
using namespace std;
#define ll long long
ll quick_pow(ll a,ll b,ll mod)
{
ll ans=1;
while(b)
{
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
ll Fermat(ll a,ll p) //a 關於 p的逆元
{
return quick_pow(a,p-2,p);
}
int main()
{
ll a,p;
double ans=0;
cin>>a>>p;
ans=Fermat(a,p);
cout<<ans<<endl;
return 0;
}
③簡化計算。還是利用快速冪