模板 2018-01-27 素数筛 素数打表 欧拉函数 欧拉定理 费马小定理

本文介绍了高效的素数筛选方法——欧拉线性筛,并提供了实现代码。此外,还详细讲解了如何利用素数筛优化欧拉函数的计算,并给出了具体的实现方式。文章最后提到了欧拉定理与费马小定理的应用。

先是素数筛

据说这个叫做欧拉线性筛, 差不多半年以前我曾经被一道有关素数的题目卡住了时限, 后来网上随便找了一个素数筛模板(捂脸逃), 过了, 这个以前的一篇博客也提到过了, 就是注释了我认为"非常精妙"的那个素数筛. 不过当时抄的那个在某些地方不是很好用, 所以又上网找了了一下其他的模板进行借鉴, 稍微增添了一点东西.

const int maxn=1000000;//这里的maxn常数可以自定义
long long prime_number[maxn];//这个不必废话,就是存放最后素数的数组,数组大小看后面给的参数,变量类型自己取舍
bool prime_check[maxn+5];//首先增添的是这个数组, check数组大小取决于你要求到多大的素数
int work_prime(long long int n)//n是你要打表到多大,比如n=10那就只打了2,3,5,7
{//函数返回值为有多少个素数
    //来自网上某博文,忘记网址了你打我啊
    //感觉很精妙,实话
    //不用先筛再遍历记录,时间快了不少
    int res,i,j;
    res=0;
    for (i=2;i<=n;i++)
    {
        if (!prime_check[i])
            prime_number[res++] = i;
        for (j=0;j<res&&i*prime_number[j]<=n;j++)
        {
            prime_check[prime_number[j]*i]=1;
            if (i%prime_number[j]==0)
                break;
        }
    }
    return res;//返回这个筛有多少个质数,并将质数依次放入prime_number数组中
}
然后就是关于素数筛开多大的问题, 这里给出一些幂次对应最接近的素数的大小和序号, 以供参考.
小于 10^1: 7 第4个
小于 10^2: 97 第25个
小于 10^3: 997 第168个
小于 10^4: 9973 第1229个
小于 10^5: 99991 第9592个
小于 10^6: 999983 第78498个
小于 10^7: 9999991 第664579个
小于 10^8: 99999989 第5761455个
小于 10^9: 999999937 第50847534个

然后就是欧拉函数

欧拉函数的意思是求1~n-1中, 与n互质的数的个数

关于公式可以由容斥原理获得, 也可以直接看学长博客(逃

然后原本的代码是这个样子的

long long phi(long long n)
{
    long long res=n,i;
    for(i=2;i*i<=n;i++)
        if(n%i==0)
        {
            res=res-res/i;
            while(n%i==0)
                n=n/i;
        }
    if(n>1)
        res=res-res/n;
    return res;
}
不过呢, 当我们使用了素数筛的话, 这个就更快了

假设我们已经打完表了, 拥有了一个素数表prime_number[]和里面存有的素数个数prime_num, 那么可以这么写

long long phi(long long n)
{
    long long res,i;
    res=n;
    for(i=0;prime_number[i]*prime_number[i]<=n&&i<prime_num;i++)
//跳出循环条件中的prime_num表示打出来的素数筛的表里面一共有多少个素数, 毕竟不能越界嘛
        if(n%prime_number[i]==0)
        {
            res=res-res/prime_number[i];
            while(n%prime_number[i]==0)
                n=n/prime_number[i];
        }
    if(n>1)
        res=res-res/n;
    return res;
}
在我们需要多次重复求欧拉函数的时候, 打表也是可以的.

void phi(long long phi[],long long maxn)
{//maxn表示你要打到多少
    int i,j;
    for(i=1;i<=maxn;i++)
        phi[i]=i;
    for(i=2;i<=maxn;i+=2)
        phi[i]/=2;
    for(i=3;i<=maxn;i+=2)
        if(phi[i]==i)
        {
            for(j=i;j<=maxn;j+=i)
                phi[j]=phi[j]-phi[j]/i;
        }
}
然后就是欧拉定理和费马小定理了

欧拉定理的描述: 若a和p互质, 则有 a^phi(p) %p =1

费马小定理的描述: 若a和p互质, 且p是质数, 则有 a^(p-1) %p =1     其实道理很简单, 因为质数p的欧拉函数值就是p-1呀

然后就有了一个有趣的逆元应用 ( a * a^(p-2) )%p =1

换句话说求a对于模p的乘法逆元, p是质数且a和p互质的话, 只要求a^(p-2) %p就行了, 参见快速幂.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值