【算法 | 板子】素数、快速幂、乘法逆元

素数

欧拉筛

    int s[maxn],p[maxn];
void prime(int n){
    int cnt=0;
	for(int i=2;i

6k+/-1

​ 质数的分布具有特点,经过证明可以得到:(大于等于5的)质数一定和6的倍数相邻,一定是6x-1或6x+1。利用这种特性。可以对整数进行筛选,只判断那些是6x-1或6x+1的整数是否为质数。

bool Prime(int n) {
    if (n<=3) 
        return n > 1;
    if (n==4) return false;
    // 只有6x-1和6x+1的数才有可能是质数
    if (n % 6 != 1 && n % 6 != 5) 
        return false;
    // 判断这些数能否被小于sqrt(n)的奇数整除
    int t = (int) sqrt(n);
    for (int i = 5; i <= t; i += 6) {
        if (n % i == 0 || n % (i + 2) == 0) {
            return false;
        }
    }
    return true;
}

快速幂

     ll fastPower(ll x, ll n,ll p) {
       ll res = 1;
       x%=p;
       while (n){
           if(n & 1)  res = (res * x )%p;
           n >>= 1;  
           x = (x * x)%p ;
       }
       return res;
    }

乘法逆元

存在判断: a和p互质,即
g c d ( a , p ) = 1 gcd(a,p)=1 gcd(a,p)=1
当p为质数,利用费马最小定理:

ll get_inv(ll x,ll p){
       return fastPower(x,p-2,p);
}

利用扩展欧几里得算法


a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcdab
​ 的一组x,y

补充:欧几里得法求最大公约数

int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
void exgcd(int a,int b,int &x,int &y){
    if(b==0){x=1;y=0;}
    int gcd=exgcd(b,a%b,y,x);
    y-=(a/b)*x;
}
int get_inv(int a,int p){
    int x=1,y=0;
    exgcd(a,p,x,y);
    return (x%p+p)%p;//防止出现负数
}

线性求逆元(直接求出1~n个)

int inv[maxn];
inv[1]=1;
for(int i=2;i<=n;i++){
    inv[i]=-(p/i)*inv[p%i];//x_inv=-k*r_inv;(推导公式)
    inv[i]=(inv[i]%p+p)%p;//保证该值一定为正
}

你可能感兴趣的:(算法板子,算法)