线性筛和素性测试

线性筛:对于每个合数,只用它的最大因子把它筛掉,避免了埃氏筛法中的重复筛选。具体写法不做证明,百度上很明白了

//线性筛求素数表
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 1000010;
int f[N], prime[N];
int table()
{
    f[0] = f[1] = 1;
    int k = 0;
    for(int i = 2; i < N; i++)
    {
        if(f[i] == 0) prime[k++] = i;
        for(int j = 0; j < k && i * prime[j] < N; j++)
        {
            f[i*prime[j]] = 1;
            if(i % prime[j] == 0) break;
        }
    }
    return k;
}
int main()
{
    int k = table();
    return 0;
}

miller-rabin素性测试:用来测试大素数,主要依据是费马小定理和二次检测定理,不做证明

//费马小定理:假设a是一个整数,p是一个素数,那么a^(p-1) ≡ 1(mod p) (0 < a < p) (费马小定理是判断素数的必要条件)
//二次探测定理:假设p是一个素数,且0<x<p,则方程x*x ≡ 1(mod p)的解为x=1和x=p-1
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll N = 1010;
ll fast_pow(ll a, ll n, ll p)
{
    ll res = 1;
    while(n)
    {
        if(n & 1) res = res * a % p;
        if((a * a) % p == 1 && a != 1 && a != p-1) return -1;
        n >>= 1;
        a = a * a % p;
    }
    return res;
}
//miller-rabin检测的正确概率不依赖被检测数a,而仅依赖于检测次数,k次检测后得到错误结果的概率为(1/4)^k
bool miller_rabin(ll n, ll num) //num
{   //注意特判几个特殊值
    if(n == 1 || n == 0) return false;
    if(n == 2) return true;
    for(ll i = 1; i <= num; i++)
    {
        ll a = rand() % (n-2) + 2;//随机数[2,n-1];
        if(fast_pow(a, n-1, n) != 1) return false;//验证a^(p-1) ≡ 1(mod p)和二次探测定理
    }
    return true;
}
int main()
{
    ll a;
    srand((unsigned int)time(NULL));
    while(~ scanf("%lld", &a))
    {
        bool flag = miller_rabin(a, 10);
        printf("%s\n", flag ? "Yes" : "No");
    }
    return 0;
}

2017/4/15.最近看了算法导论关于数论的在章节,对miller_rabin加深了理解,按照算法导论上的伪代码实现了一下,跟之前的版本稍微有些不同。对于 ap11(modp) ,有 p1=2tu ,其中 t1u 为奇数,先计算出 au ,然后对结果连续平方t次计算 ap1modp

//费马小定理:假设a是一个整数,p是一个素数,那么a^(p-1) ≡ 1(mod p) (0 < a < p) (费马小定理是判断素数的必要条件)
//二次探测定理:假设p是一个素数,且0<x<p,则方程x*x ≡ 1(mod p)的解为x=1和x=p-1
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll N = 1010;
ll mod_mul(ll a, ll n, ll p)//之所以写这个函数,是为了防止类似a*a%p中a*a溢出
{
    ll res = 0;
    while(n)
    {
        if(n & 1) res = (res + a) % p;
        n >>= 1;
        a = (a + a) % p;
    }
    return res;
}
ll mod_pow(ll a, ll n, ll p)
{
    ll res = 1;
    while(n)
    {
        if(n & 1) res = mod_mul(res, a, p);
        n >>= 1;
        a = mod_mul(a, a, p);
    }
    return res;
}
//miller-rabin检测的正确概率不依赖被检测数a,而仅依赖于检测次数,k次检测后得到错误结果的概率为(1/4)^k
bool miller_rabin(ll p, int num) //num
{   //注意特判几个特殊值
    if(p == 1 || p == 0) return false;
    if(p == 2) return true;
    ll m = p-1;
    int tot = 0;
    while(! (m&1)) m >>= 1, tot++;
    for(int i = 1; i <= num; i++)
    {
        ll a = rand() % (p-2) + 2;//随机数[2,n-1];
        a = mod_pow(a, m, p);
        for(int j = 1; j <= tot; j++) //验证a^(p-1) ≡ 1(mod p)和二次探测定理
        {
            ll b = mod_mul(a, a, p);
            if(b % p == 1 && a != 1 && a != p-1) return false;
            a = b;
        }
        if(a != 1) return false;
    }
    return true;
}
int main()
{
    ll a;
    srand((unsigned int)time(NULL));
    while(~ scanf("%lld", &a))
    {
        bool flag = miller_rabin(a, 10);
        printf("%s\n", flag ? "Yes" : "No");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值