GCD + 素数+快速幂

1.欧几里得算法

求解最大公约数,时间复杂度在O(log max(a,b))以内,可以看出,辗转相除法是非常高效的

int gcd(int a,int b)
{
    return (b==0)?a:gcd(b,a%b);
}

2.扩展欧几里得算法

求解方程a*x+b*y=gcd(a,b),a、b、x、y均为整数,时间复杂度和辗转相除法是相同的,函数返回gcd(a,b)。

int gcd(int a,int b)
{
    return (b==0)?a:gcd(b,a%b);
}
int extgcd(int a,int b,int& x,int& y)
{
    int d=a;
    if(b!=0){
        d=extgcd(b,a%b,y,x);
        y-=(a/b)*x;
    }
    else{
        x=1;
        y=0;
    }
    return d;
}

3.素数测试

//素性测试O(√n)
bool is_prime(int n)
{
    for(int i=2;i*i<=n;i++){
        if(n%i==0) return false;
    }
    return n!=1;//n等于1是例外
}
//约数枚举O(√n)
vector<int> divisor(int n)
{
    vector<int> res;
    for(int i=2;i*i<=n;i++){
        if(n%i==0){
            res.push_back(i);
            if(i!=n/i) res.push_back(n/i);
        }
    }
    return res;
}
//整数分解O(√n)素数因子
map<int,int> prime_factor(int n)
{
    map<int,int> res;
    for(int i=2;i*i<=n;i++){
        while(n%i==0){
            ++res[i];
            n/=i;
        }
    }
    if(n!=1) res[n]=1;
    return res;
}

其中map第一个int是n的素数因子,对应的第二个int是这个因子的个数

2.埃式筛法

给定一个正整数n,请问n以内有多少个素数。

首先将2到n的所有整数记下来,其中最小的整数2是素数,将表中2的倍数划去。表中最小的整数是3,它不能被更小的数整除,所以是素数,将表中3的倍数划去,以此类推,表中剩余的最小数字是m,则m就是素数。这样反复操作即可枚举得到n以内的所有素数,时间复杂度为O(nloglogn),可以看作是线性时间。

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

3.区间筛法

给定整数a、b,求区间[a,b)内有多少个素数

b以内的合数的最小质因数一定不超过√b。如果有√b以内的素数表,就可以把埃式筛法用到区间[a,b)上了。也就是说,先做好[2,√b)和[a,b)的表,然后从[2,√b)表中筛选素数的同时,也将其倍数从[a,b)的表中划去,最后剩下的就是[a,b)内的素数了。

typedef long long ll;
bool is_prime[1000000+5];
bool is_prime_small[1000000+5];
//对区间[a,b)内的整数执行筛法。is_prime[i-a]=true→i是素数
void segment_sieve(ll a,ll b)
{
    for(int i=0;(ll)i*i<b;i++) is_prime_small[i]=true;
    for(int i=0;i<b-a;i++) is_prime[i]=true;
    for(int i=2;(ll)i*i<b;i++){
        if(is_prime_small[i]){
            for(int j=2*i;(ll)j*j<b;j+=i) is_prime_small[i]=false;//筛[2,√b)
            for(ll j=max(2ll,(a+i-1)/i)*i;j<b;j+=i) is_prime[j-a]=false;//筛[a,b)
            //2LL是2的长整数形式
            //((a+i-1)/i)*i是满足>=a&&%i==0的离a最近的数
            //也可以写成(a%i==0)?a:(a/i+1)*i
        }
    }
}

4.快速幂运算

typedef long long ll;
ll mod_pow(ll x,ll n,ll mod)
{
    ll res=1;
    while(n>0){
        if(n&1) res=res*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return res;
}

原文地址:https://www.cnblogs.com/zllwxm123/p/9542621.html

时间: 2024-10-03 09:33:32

GCD + 素数+快速幂的相关文章

POJ3641 Pseudoprime numbers(快速幂+素数判断)

POJ3641 Pseudoprime numbers p是Pseudoprime numbers的条件: p是合数,(p^a)%p=a;所以首先要进行素数判断,再快速幂. 此题是大白P122 Carmichael Number 的简化版 /* * Created: 2016年03月30日 22时32分15秒 星期三 * Author: Akrusher * */ #include <cstdio> #include <cstdlib> #include <cstring&g

记一次使用快速幂与Miller-Rabin的大素数生成算法

大家都知道RSA的加密的安全性就是能够找到一个合适的大素数,而现在判断大素数的办法有许多,比如Fermat素性测试或者Miller-Rabin素性测试,而这里我用了Miller-Rabin素性测试的算法,具体的理论我写到下面. 算法的理论基础: Fermat定理:若n是奇素数,a是任意正整数(1≤ a≤ n?1),则 a^(n-1) ≡ 1 mod n. 2.  如果n是一个奇素数,将n?1表示成2^s*r的形式,r是奇数,a与n是互素的任何随机整数,那么a^r ≡ 1 mod n或者对某个j

poj3696 快速幂的优化+欧拉函数+gcd的优化+互质

这题满满的黑科技orz 题意:给出L,要求求出最小的全部由8组成的数(eg: 8,88,888,8888,88888,.......),且这个数是L的倍数 sol:全部由8组成的数可以这样表示:((10^x)-1)*(8/9) 那么有m=((10^x)-1)*(8/9)=k*L,answer即满足条件的最小的x 性质1:若ax=by且a和b互质,那么说明a中没有任何b的质因子,b的质因子一定都在x里.所以x是b的倍数. 所以先想方设法在等式中构造两个互质的数以便化简.我们取p=8/gcd(8,L

UVA - 10006 - Carmichael Numbers (快速幂+素数判断)

题目传送:UVA - 10006 思路:就是快速幂暴力过去就行了,然后要注意点细节,就是快速幂的时候会爆int,然后就是先判断是否为素数,是素数就直接输出结果is normal,不然会超时 AC代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #inclu

UVA10006 - Carmichael Numbers(筛选构造素数表+快速幂)

UVA10006 - Carmichael Numbers(筛选构造素数表+快速幂) 题目链接 题目大意:如果有一个合数,然后它满足任意大于1小于n的整数a, 满足a^n%n = a;这样的合数叫做Carmichael Numbers.题目给你n,然你判断是不是Carmichael Numbers. 解题思路:首先用筛选法构造素数表,判断n是否是合数,然后在用快速幂求a^2-a^(n - 1)是否满足上述的式子.快速幂的时候最好用long long ,防止相乘溢出. 代码: #include <

POJ 3641 素数打表+快速幂 简单题

给出2个数,p和a,2<p<=1e9,1<a<p 若p满足下面2个条件,输出yes,否则输出no 1.p不是素数 2.有a^p=a(mod p) 先判断第一个条件: 本来想用一个数组is_prime[i]表示i是不是素数的,明显,这里p太大,数组开不下 若p不是素数的话, 则p必有p=b*c,其中b<=c, 则(sqrt(p))^2=b*c,则b<=sqrt(p)<=10^4.5<10^5 所以若在10^5内存在数b满足b<p&&p%b

取模性质,快速幂,快速乘,gcd和最小公倍数

一.取模运算 取模(取余)运算法则: 1. (a+b)%p=(a%p+b%p)%p; 2.(a-b)%p=(a%p-b%p)%p; 3.(a*b)%p=(a%p * b%p)%p; 4.(a^b)%p=(   (a%p)^b  )%p; 5. (  (a+b)%p+c  )%p=( a+(b+c)%p  )%p; 6.( a*(b*c)%p )%p =( c*(a*b)%p )%p; 7.( (a+b)%p*c )%p= ( (a*c)%p + (b*c)%p )%p; 几条重要性质: 1.a≡

GCD&amp;&amp;素筛&amp;&amp;快速幂 --A - Pseudoprime numbers

Fermat's theorem states that for any prime number p and for any integer a > 1, ap = a (mod p). That is, if we raise a to the pth power and divide by p, the remainder is a. Some (but not very many) non-prime values of p, known as base-a pseudoprimes,

poj 2888 Magic Bracelet(Polya+矩阵快速幂)

Magic Bracelet Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 4990   Accepted: 1610 Description Ginny’s birthday is coming soon. Harry Potter is preparing a birthday present for his new girlfriend. The present is a magic bracelet which