数论

数论

根号算法

bool isprime(int x)
{
    if(x==0||x==1) return 0;
    if(x==2) return 1;
    for(int i=3;i<=sqrt(x);i++)
    {
        if(x%i==0) return 0;
    } 
    return 1;
} 
  • 单次时间复杂度:\(O(\sqrt x)\)
  • 判断1-n的素数个数:\(O(x\sqrt x)\)

埃氏筛法

  • 先将2到n范围内的整数列出来,其中2是最小的素数。
  • 将表中所有的2的倍数划去,表中剩下的最小的数字就是3,他不能被更小的数整除,所以3是素数。
  • 再将表中所有的3的倍数划去……以此类推;
  • 如果表中剩余的最小的数是m,那么m就是素数。
  • 然后将表中所有m的倍数划去,像这样反复操作,就能依次枚举n以内的素数。
2 3 4 5 ... 13 14 15 16 17 18 19 20
2 3 - 5 ... 13 - 15 - 17 - 19 -
2 3 - 5 ... 13 - - - 17 - 19 -
  • 时间复杂度为\(O(nlog(logn))\)

例:给定一个正整数n(n<=10^6),问n以内有多少个素数?

int prime[MAXN];//第i个素数
bool is_pri[MAXN+10];//is_pri[i]表示i是素数
//返回n以内素数的个数
int sieve(int n)
{
    int p=0;
    for(int i=0;i<=n;i++) is_pri[i]=true;
    is_pri[0]=is_pri[1]=false;
    for(int i=2; i<=n; i++)
    {
        if(is_pri[i])
        {
            prime[++p]=i;
            for(int j=2*i; j<=n; j+=i) is_pri[j]=false;
        }
    }
    return p;
}

区间素数筛:给定两个正整数\(a,b(a,请问[a,b)内有多少个素数?

#include
using namespace std;
bool pri[1000000+10];
bool ispri[10000000+10];//ispri[i-a]=true代表i是素数
void getpri()
{
    memset(pri,true,sizeof(pri));
    pri[0]=pri[1]=0;
    for(int i=2;i<=1000000;i++)
    {
        if(pri[i]){
            for(int j=2*i;j<=1000000;j+=i)pri[j]=0;
        }
    }
}
int main(){
    long long a,b;
    scanf("%lld%lld",&a,&b);
    getpri();
    memset(ispri,true,sizeof(ispri));
    for(long long i=2;i*i

欧拉

欧拉筛

  • 欧拉筛法的基本思想 :在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。
int prime[maxn];
int visit[maxn];
void Prime()
{
    mem(visit,0);
    mem(prime, 0);
    for (int i = 2;i <= maxn; i++) 
    {
        cout<<" i = "<
  • 上面有一个visit[i*prime[j]] = 1;,这里解释一下
    • 这里不是用i的倍数来消去合数,而是把prime里面纪录的素数,升序来当做要消去合数的最小素因子。
    • i是在消去合数中的作用是当做倍数的。
  • 还有一个i % prime[j] == 0
    • 当 i是prime[j]的倍数时,i=kprime[j],如果继续运算j+1,i * prime[j+1]=prime[j] * kprime[j+1],这里prime[j]是最小的素因子,当i=k * prime[j+1]时会重复,所以才跳出循环。
    • 举个例子 i=8,j=1,prime[j]=2,如果不跳出循环,prime[j+1]=3,83=243=212,在i=12时会计算。因为欧拉筛法的原理便是通过最小素因子来消除。
    • 附上欧拉筛代码:
    /*求小于等于n的素数的个数*/
    #include
    #include
    using namespace std;
    int main()
    {
      int n, cnt = 0;
      int prime[100001];//存素数 
      bool vis[100001];//保证不做素数的倍数 
      scanf("%d", &n);
      memset(vis, false, sizeof(vis));//初始化 
      memset(prime, 0, sizeof(prime));
      for(int i = 2; i <= n; i++)
      {
          if(!vis[i])//不是目前找到的素数的倍数 
          prime[cnt++] = i;//找到素数~ 
          for(int j = 0; j

欧拉函数

  • 欧拉函数\(φ(x)\)的值为在[1,x)的区间内与x互质的数的个数
  • 通式:\(φ(x)=\prod_{i=1}^xn(1−\frac{1}{p_i})其中p_1,p_2,...,p_n\)为x的所有质因数,x是不为0的整数。\(φ(1)=1\)
  • 注意:每种质因数只一个。比如\(12=2×2×3\)那么\(φ(12)=12×(1−\frac{1}{2})×(1−\frac {1}{3})=4\)
  • 介绍几个性质:
    • 若n是质数p的k次幂,则\(φ(x)=p^k−p^{k−1}=(p−1)p^{k−1}\),因为除了p的倍数外,其他数都跟n互质。
    • 积性函数——若m,n互质,\(φ(mn)=φ(m)φ(n)\)
    • 当n为质数时,\(φ(2x)=φ(x)\),其实与上述类似。
    • 若n为质数则\(φ(x)=x−1\),这个挺重要的。
    • 一个数的所有质因子之和S是\(S=\frac {nφ(n)}{2}\)
    //用通式算的
    int euler(int n){ //返回euler(n)
      int res=n,a=n;
      for(int i=2;i*i<=a;i++){
          if(a%i==0){
              res=res/i*(i-1);//先进行除法是为了防止中间数据的溢出
              while(a%i==0) a/=i;
          }
      }
      if(a>1) res=res/a*(a-1);
      return res;
    }
    //筛选法打欧拉函数表
    #define Max 1000001
    int euler[Max];
    void Init()
    {
       euler[1]=1;
       for(int i=2;i
#include 
using namespace std;
typedef long long ll;
#define N 100000
int primes[N], euler[N], cnt;
bool st[N];
/* 欧拉函数
可以在 O(n) 的时间复杂度内求出 1~n中所有数的欧拉函数 同时也能算质数
质数存在primes[]中(用cnt统计<=n的素数个数),euler[i] 表示 i的欧拉函数*/
int get_eulers(int n) 
{
    euler[1] = 1;
    for (int i = 2; i <= n; i ++ ) 
    {
        if (!st[i]) 
        {
            primes[cnt ++ ] = i;
            euler[i] = i - 1;
        }
        for (int j = 0; j < cnt && i * primes[j] <= n; j ++ ) 
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) 
            {
                euler[i * primes[j]] = euler[i] * primes[j];
                break;
            }
            euler[i * primes[j]] = euler[i] * (primes[j] - 1);
        }
    }
    return cnt;
}
 
int main(void) 
{
    get_eulers(101);
    for (int i = 0 ; i < cnt; i++) 
    {
        cout << i << " " << primes[i] << endl;
    }
    cout << endl;
    // 输出1到100每个数的欧拉函数值
    for (int j = 1 ; j < 101; j++) 
    {
        cout << j << " " << euler[j] << endl;
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

你可能感兴趣的:(数论)