线性筛素数+欧拉函数

欧拉函数

定义

  在数论中 ,对正整数n,欧拉函数是小于或等于n的数中与n互质的数的数目,记做phi(n)。
如φ(8)=4,因为1,3,5,7均和8互质。

性质
  1.   若n=(p1a1) * (p2a2) * …… * (pkak) (为N的分解式),则φ(n)=n * (1-1/p1) * (1-1/p2) * …… * (1-1/pk) 如果n为某一个素数p,则φ(p )=p-1 如果n为任意两个数a和b的积,那么φ(a*b)=φ(a)*φ(b) 如果i mod p = 0, 那么phi(i * p)=p * phi(i)
  2.   p^k的欧拉函数
    对于给定的一个素数p,我们知道φ ( p) = p-1。
    假设一个整数n是p的k次幂,也就是 n = pk,k∈N+
    容易证明 φ(n) = pk - p(k-1)
    证明: 已知小于pk的正整数个数为pk-1个,其中
    和pk不互质的正整数有{p×1,p×2,…,p×(p(k-1)-1)}共计p(k-1)-1个
    所以φ(n) = pk-1 - (p(k-1)-1) = pk - p(k-1)
积性函数

  对于正整数n的一个函数 f(n),当中f(1)=1且当a,b互质,f(ab)=f(a)f(b),在数论上就称它为积性函数。 若某函数f(n)符合f(1)=1,且就算a,b不互质,f(ab)=f(a)f(b),则称它为完全积性函数。

欧拉函数,gcd(n,k)(当k固定时)都是积性函数

线性筛代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<deque>
#include<iostream>
using namespace std;
typedef long long  LL;
const int N = 100009;
int check[N];  
int prime[N]; //存储素数
int phi[N];  //存储欧拉函数
int cnt;
void is_prime(int n)
{
    int i,j;
    cnt=0;
    phi[1]=1;
    for(i=2; i<=n; i++)
    {
        if(!check[i])//判断是不是素数
        {
            prime[cnt++]=i;//存储素数
            phi[i]=i-1;  //欧拉函数
        }
        for(j=0; j<cnt; j++)//遍历所有的素数
        {
            if(i*prime[j]>n)
                break;
            check[i*prime[j]]=1;  //将出现过的所有的素数的i倍标记为合数
            //说明i的因子中含有prime[j],即i唯一分解后,最小质 因子是prime[j]。
            //因为prime[k](k > j) 都是大于prime[j]的,根据 线性筛的思想(保证每个合数只会被它的最小质因数筛去),所以prime[j]之后的素数都不能去筛prime[j]]*i, break.
            if(i%prime[j]==0)    //例:当i等于6时,i = 2^2 * 3,所以任何数与i相乘, 乘积的最小质因子肯定是要小于等于2的。
            {
                //(下面这一段注释是我之前写的,现在无法理解了.....)
                /*因为 i%prime[j]==0 ,所以i 是 prime[j] 的倍数, i 就可以看成 prime[j]*k , 这样
                               就相当于筛去 prime[i]的k*prime[j+1] 倍,但是这个数不应当现在被处理,而是在 i==prime[j+1]*k时被筛掉 */
                phi[i*prime[j]]=phi[i]*prime[j];    // 因为prime[j] 是质数,所 以prime[j] 不可再分解,因此 i*prime[j] 的分解形式为i的分解形式再乘以prime[j],
                // 欧拉函数性质: 如果i mod p = 0, 那么phi(i * p)=p * phi(i)
                break;
            }
            else
                phi[i*prime[j]]=phi[i]*(prime[j]-1);
                //当 i 不是 prime[j] 的倍数的时候,欧拉函数为完全积性函数,满足积性函数的特点
            }
        //欧拉函数性质: 设m和n 是互质的正整数,那么phi(mn) = phi(m) * phi(n)
    }
}
int main()
{
    int i;
    is_prime(100);
    for(i=0; i<cnt; i++)
    {
        printf("%d %d\n",prime[i],phi[prime[i]]);
    }
    return 0;
}

POJ 2407

#include<stdio.h>
#include<stdlib.h>
long long eular(long long n)
{
    long long ret=n,i;
    for(i=2; i*i<=n; i++)
    {
        if(n%i==0)
        {
            n/=i;
            ret=ret/i*(i-1);
            while(n%i==0)
            {
                n/=i;
            }
        }
    }
    if(n>1) ret=ret/n*(n-1);
    return ret;
}
int main ()
{
    long long n,s;
    while(~scanf("%lld",&n))
    {
        if(n==0)
            break;
        s=eular(n);
        printf("%lld\n",s);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值