我们用来判定素数是用到的是费马小定理:
对于一个数 p,若ap ≡ a(mod p),则 p 几乎为素数
但如果 n 是一个合数,且满足上面的这个式子,则称这个数为伪素数:
如果n是一个正整数,如果存在和n互素的正整数a满足 an-1 ≡ 1(mod n),我们说n是基于a的伪素数。如果一个数是伪素数,那么它几乎肯定是素数。
但我们不能通过换一个底数去消除所有的错误,因为对于所有的非零整数,我们总能找到满足该式子的合数,它们被称为 Carmichael 数,但它们的数量很少,在小于 100 000 000 的数种只有 255 个 Carmichael 数。
所以我们在判断素数时可以引用另一种测试方法 Miller-Rabin 随机性素数测试方法:
不断选取不超过n-1的基b(s次),计算是否每次都有bn-1 ≡ 1(mod n),若每次都成立则n是素数,否则为合数。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cmath>
using namespace std;
typedef long long ll;
ll n;
int s[]={2,3,5,7,11,13,17,19,23,29};
ll mul(ll a,ll b)
{
ll ans = 0;
for(ll i = a; i; i >>= 1)
{
if (i & 1)
ans = (ans + b) % n;
b = (b + b) % n;
}
return ans % n;
}
ll ksm(ll a,ll b)
{
ll ans = 1;
for (ll i = a; i; i >>= 1)
{
if (i & 1)
ans = mul(ans,b) % n;
b = mul(b, b) % n;
}
return ans%n;
}
bool check()
{
if (n == 2)
return 1;
if(n<2 || !(n&1))
return 0;
for (int i = 0; i < 10; i++)
{
if ((ksm(n-1, s[i])%n) != 1)
return 0;
}
return 1;
}
int main()
{
cin >> n;
if (check())
puts("Yes");
else
puts("No");
return 0;
}