这篇文章我们将介绍数论当中几个很重要的定理:威尔逊定理、费马小定理以及欧拉定理,并讨论一些基于这些定理的算法。
首先我们给出费马小定理:如果p是素数,并且gcd(a,p) = 1 , 那么有a^(p-1) = 1(mod p)。
而关于这个定理的证明,也是不难理解的。
在证明之前,我们先需要知道这样两个引理。
引理1:若a、b、c为任意3个整数,且gcd(m,c) = 1,则当ac = bc(mod m)时,有a = b (mod m)。
引理2:设m是一个整数,且m>1,b是一个整数且gcd(m,b)=1.如果a1,a2,a3,a4,…am是模m的一个完全剩余系,那么ba[1],ba[2],ba[3],ba[4],…ba[m]也构成模m的一个完全剩余系。
这里需要解释一下的是,所谓完全剩余系,即{a1,a2,a3,a4,…am}中任意一个元素ai % m != 0。针对引理1,通过同余式本身的特点,都十分易证,随后再基于引理1,引理2也不难得证。这里便不再累述。 有了这两个引理做铺垫,下面便可以开始费马小引理的证明了。
构造素数p的完全剩余系P = {1,2,3,……p-1}。
因为gcd(a,p) = 1,由引理2得素数p的新的完全剩余系:A = {a,2a,3a,……(p-1)a}。
我们选出A、P中第i个元素,由引理1得,Ai = Pi(mod p),因此我们容易得到如下等式。
1 * 2 * 3 *……(p-1) = a * 2a * 3a * ……(p-1)a (mod p)
等式两边同除(p - 1)!,得到a^(p-1) = 1 (mod p),定理得证。
既然知道了费马小定理的内容和证明了,这里我们就用它进行一下拓展利用。
首先我们知道,在费马小定理的等式a^(p - 1) = 1 (mod p)中,如果p是素数,那么等式是成立的。
即 isprime(p) = 1 => a^(p - 1) = 1 (mod p) 。 那么我们根据逆否命题与原命题的等价性,可以得到,a^(p - 1) != 1 (mod p) => isprime(p) = 0。
那么逆命题和否命题与原命题是否等价呢?如果等价,我们岂不是可以通过判断是否满足费马小定理的等式来判断p是否为素数了?
实践表明,满足费马小定理的a、p组合中,p是可以为合数的,不妨自己举几个例子。 因此对于满足费马小定理等式的a、p,有这样的定义。如果p是合数,则称p是以a为基的伪素数。
我们不妨通过一个题目来理解一下所谓伪素数的概念。(Problem source:pku 3641)
Description
Fermat‘s theorem states that for any prime number p and for any integer a > 1, ap = a (mod p). That is, if we raise a to the pth power and divide by p, the remainder is a. Some (but not very many) non-prime values of p, known as base-a pseudoprimes, have this property for some a. (And some, known as Carmichael Numbers, are base-a pseudoprimes for all a.)
Given 2 < p ≤ 1000000000 and 1 < a < p, determine whether or not p is a base-a pseudoprime.
Input
Input contains several test cases followed by a line containing "0 0". Each test case consists of a line containing p and a.
Output
For each test case, output "yes" if p is a base-a pseudoprime; otherwise output "no".
题目大意:基于伪素数的概念,给出a、p,请你判断p是否是以a为基的伪素数。
数理分析:有了上文对伪素数概念的较少,我们知道,伪素数首先必须是合数,然后需要满足费马小定理。
编程实现:在判断是否是伪素数的时候,由于是判断单个数字,所以使用朴素的判断法即可。而判断是否满足费马小定理的时候,则用到了我们在之前讨论过的乘法快速幂算法。 参考代码如下。
#include<iostream> #include<math.h> using namespace std; bool ifprime(long long n) { long long i; int iffind = 0; if(n == 2 || n == 1) return 1; else { for(i = 2;i <= sqrt(n + 0.0);i++) if(n%i == 0) { iffind = 1; break; } if(iffind) return 0; else return 1; } } long long quick_mod(long long a , long long b , long long m) //快速幂取模,计算a^b(mod m)的值 { long long ans = 1; while(b) { if(b&1) { ans = (ans * a)%m; b--; } b /= 2; a = a * a %m; } return ans; } int main() { long long n , a, p ,b; while(cin >> p >> a) { if(p == 0 && a == 0) break; if(ifprime(p)) cout<<"no"<<endl; else { long long ans = quick_mod(a,p,p); if(ans == a) cout<<"yes"<<endl; else cout<<"no"<<endl; } } return 0; }