Number Theory Templates - Sieve of Prime Numbers, Divisors, Euler Functions

Number Theory

Determining Prime Numbers: Trial Division

In an integer greater than 1, if it only contains two divisors of 1 and itself, it is called a prime number/prime number It
must be O(sqrt(n))
insert image description here
Not recommended:
i*i<n There is an overflow risk
i<n /i must not overflow
i<sqrt(n) function is called every time

Decomposing Prime Factors: Trial Division

Not necessarily O(sqrt(n))
Best O(logn), worst O(sqrt(n))
According to the Fundamental Theorem of Arithmetic, every positive integer can be represented in a unique way, regardless of the order of arrangement to be the product of its prime factors.

n=p1a1 x p2a2 x p3a3 x…… x pnan

For example, a number 16 first finds the prime factor of 2 when decomposing, and then because 16/2 can still be /2, it will generate a power on the prime factor of 2

Unoptimized version: find the divisible factor from 2~n and calculate the power.
Dissatisfied with this unoptimized version in advance

There is a property here: n contains at most one factor greater than sqrt(n).
The proof is by contradiction: if there are two factors greater than sqrt(n), the multiplication will be greater than n, contradicting. So we find that there is at most one factor greater than sqrt
(n), and optimize it. Consider first that the code is smaller than sqrt(n), and the judgment of the code and the prime number is similar.
Finally, if n is still > 1, it means that there is a unique prime factor greater than sqrt(n) , and the output can be done.
insert image description here

#include <iostream>
void find(int n){
    
    
    int i;
    for(i=2;i<=n/i;i++){
    
    
        int s=0;
        while(n%i==0){
    
    
            n/=i;
            s++;
        }
        if(s>0)printf("%d %d\n",i,s);
    }
    if(n>1)printf("%d %d\n",n,1);//大于sqrt(n)的唯一质因子
}
int main(){
    
    
    int n;
    scanf("%d",&n);
    
    while(n--){
    
    
       int num;
       scanf("%d",&num);
       find(num);
       puts("");
    }
    
    return 0;
}

Prime number

insert image description here

1. The most common sieve method O(nlogn)

Sieve out the multiples of all numbers in turn, leaving n/n that is a prime number nlnn
n (n/2+n/+...+n/n)

Prime Number Theorem:
There are n/lnn prime numbers from 1 to n

#include <iostream>
const int N=1e6+100;
bool st[N];
int prim[N];
int cnt;
int n;
void get_primes2(){
    
    
    for(int i=2;i<=n;i++){
    
    

        if(!st[i]) primes[cnt++]=i;//把素数存起来
        for(int j=i;j<=n;j+=i){
    
    //不管是合数还是质数,都用来筛掉后面它的倍数
            st[j]=true;
        }
    }
}
int main(){
    
    
   
    scanf("%d",&n);
    get_prim();
    printf("%d",cnt);
    
    return 0;
}

2. Eh's sieve method O(nloglogn)

Sieve all the multiples of prime numbers in turn, leaving all prime numbers nlnn/lnn=n

void get_primes1(){
    
    
    for(int i=2;i<=n;i++){
    
    
        if(!st[i]){
    
    
            primes[cnt++]=i;
            for(int j=i;j<=n;j+=i) st[j]=true;//可以用质数就把所有的合数都筛掉;
        }
    }
}

3.3. Linear sieve method O(n)

Core: composite numbers will only be sieved by the smallest prime factor, and each number will only be sieved once, so it is linear
insert image description here

void get_primes(){
    
    
    //外层从2~n迭代,因为这毕竟算的是1~n中质数的个数,而不是某个数是不是质数的判定
    for(int i=2;i<=n;i++){
    
    
        if(!st[i]) primes[cnt++]=i;
        for(int j=0;primes[j]<=n/i;j++){
    
    //primes[j]<=n/i:变形一下得到——primes[j]*i<=n,把大于n的合数都筛了就
        //没啥意义了
            st[primes[j]*i]=true;//用最小质因子去筛合数

            //1)当i%primes[j]!=0时,说明此时遍历到的primes[j]不是i的质因子,那么只可能是此时的primes[j]<i的
            //最小质因子,所以primes[j]*i的最小质因子就是primes[j];
            //2)当有i%primes[j]==0时,说明i的最小质因子是primes[j],因此primes[j]*i的最小质因子也就应该是
            //prime[j],之后接着用st[primes[j+1]*i]=true去筛合数时,就不是用最小质因子去更新了,因为i有最小
            //质因子primes[j]<primes[j+1],此时的primes[j+1]不是primes[j+1]*i的最小质因子,此时就应该
            //退出循环,避免之后重复进行筛选。
            if(i%primes[j]==0) break;
        }
    }

}

approximation

Finding Divisors: Trial Division

d is a number sub-number, n/d is also a number sub-number, you can only choose the smaller one when enumerating
insert image description here

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

void find(int n){
    
    
    vector<int>a;
    for(int i=1;i<=n/i;i++){
    
    
        if(n%i==0){
    
    
            a.push_back(i);
            if(n/i!=i)a.push_back(n/i);
        }
    }
    sort(a.begin(),a.end());
    
    for(auto t:a){
    
    
       cout<<t<<' ';
    }
}
int main(){
    
    
    int n;
    scanf("%d",&n);
    while(n--){
    
    
        int num;
        scanf("%d",&num);
        find(num);
        puts("");
    }
    return 0;
}

find the number

At the same time, you can find the number of multiples and the number
of divisors:

insert image description here

Number of multiples: = about 1500 with the largest number in the range of
insert image description here
nlogn ints

find sum of divisors

insert image description here
insert image description here

#include <iostream>
#include <unordered_map>

using namespace std;
const int mod=1e9+7;
typedef long long LL;


int main(){
    
    
    int n;
    scanf("%d",&n);
    
    unordered_map<int, int> hash;
    
    while(n--){
    
    
         
        int num;
        scanf("%d",&num);
        
        for(int i=2;i<=num/i;i++){
    
    
            
            while(num%i==0){
    
    
             num/=i;
             hash[i]++;
            }
            
            
        }
        if(num>1)hash[num]++;  
    }
    
    LL ans=1;
    
    for(auto t:hash){
    
    
       int p=t.first, a=t.second;                                                                                                                             a=t.second;
       LL pt=1;
       while(a--){
    
    
           pt=(pt*p+1)%mod;
       }
       ans=ans*pt%mod;
    }
    
 
    printf("%lld",ans);
    
    return 0;
}

Finding the greatest common divisor: Euclidean algorithm O(logn)

Also known as tossing and dividing

If d can divide a, d can divide b,
then d can divide a+b, d can also divide ax+by

Greatest common divisor gcd(a,b)=gcd(b,a mod b)
insert image description here
insert image description here
insert image description here
insert image description here

#include <iostream>
using namespace std;
int gcd(int a,int b){
    
    
   return b?gcd(b,a%b):a;
}
int main(){
    
    
    int n;
    scanf("%d",&n);
    while(n--){
    
    
      int a,b;
      scanf("%d%d",&a,&b);
      int ans=gcd(a,b);
      printf("%d\n",ans);
    }
    return 0;
}

Euler function

The bottleneck is in decomposing the prime factors, and the time complexity of decomposing the prime factors is O(sqrt(n))
insert image description here
The number of numbers from 1 to n that are relatively prime to n is relatively
prime : that is, the two numbers do not contain a common prime factor
insert image description here
. Count is irrelevant
insert image description here
Proof:
insert image description here

Find the Euler function

insert image description here

#include <iostream>
using namespace std;
int main(){
    
    
    int n;
    scanf("%d",&n);
    while(n--){
    
    
        int x;
        scanf("%d",&x);
       
        int res=x;
        
        for(int i=2;i<=x/i;i++){
    
    
            if(x%i==0){
    
    
                res=res/i*(i-1);
                while(x%i==0){
    
    
                    x/=i;
                }
            }
            
        }
        if(x>1)res=res/x*(x-1);
        printf("%d\n",res);
    }
    return 0;
}

Sieve method to find Euler function

insert image description here

#include <iostream>
using namespace std;
const int N=1e6+100;
typedef long long LL;
int prime[N],cnt;
int phi[N];
bool st[N];
int n;
void get_euler(){
    
    
    
    phi[1]=1;
    
    for(int i=2;i<=n;i++){
    
    
        if(!st[i]){
    
    
            prime[cnt++]=i;
            phi[i]=i-1;
        }
        
        for(int j=0;prime[j]<=n/i;j++){
    
    
            st[i*prime[j]]=true;
            
            if(i%prime[j]==0){
    
    
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }else{
    
    
                phi[i*prime[j]]=phi[i]*(prime[j]-1);
            }
            
        }
    }
    
    LL ans=0;
    
    for(int i=1;i<=n;i++){
    
    
        ans+=phi[i];
    } 
    
    printf("%lld",ans);
     
}
int main(){
    
    
    scanf("%d",&n);
    get_euler();
    return 0;
}

Supplement: Euler's Theorem
insert image description here
Proof:
insert image description here

Special case:
p is a prime number
insert image description here

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324162746&siteId=291194637