初等数论1

1.素数

欧拉筛法(线性筛法)
用每个数(可以为合数)与已经筛出的质数筛掉别的合数。
欧拉筛法做到线性的秘诀在于保证每个合数只被它最小的素因子筛一次。
若p|i,那么让p大的素数来筛出iq时, iq=q(ip)p ,所以不是最小素因子,可以在访问到p的时候跳出循环了。

const int N = 100000 + 10;
int is_prime[N], prime[N], tot;//is_prime[p] == 0表示p为素数,tot为素数的个数 
void find_prime(){
    is_prime[1] = 0;
    for(int i = 2; i < N; i++){
        if(!is_prime[i])
            prime[++tot] = i;
        for(int j = 1; j <= tot && i * prime[j] < N; j++){
            is_prime[i*prime[j]] = 1;
            if(i % prime[j] == 0) break;//以此做到线性 
        }
    }
}

2.同余

扩展欧几里得算法(ex-gcd)
给定a,b,c,求满足 ax+by=c 的一组解
显然若有解 gcd(a,b)=c ,然后可以转化为求 ax+by=1
类似于gcd一样的迭代,考虑若 bx+(a%b)y=1 的解,因为
a%b=a(a/b)b
所以有解
x=y y=x(a/b)y

int x, y;
int exgcd(int a, int b){
    if(b == 0){
        x = 1, y = 0;
        return a;
    }
    int tmp1 = exgcd(b, a%b);
    int tmp = x;
    x = y;
    y = tmp - (a/b)*y;
    return tmp1;
}
//返回值顺便求出了a,b的最大公约数g,此时得到一组解(x, y),则(x + kb/g, y - ka/g)为其他解 
//求整数x和y,使得ax+by=d,且|x|+|y|最小。其中d=gcd(a,b)
void exgcd(LL a, LL b, LL &d, LL &x, LL &y){
    if(b == 0) d = a, x = 1, y = 0;
    else exgcd(b, a % b, d, y, x), y -= x * (a / b);
}

同余和逆元
对于整数a,b,m,如果 a%m=b%m ,称a和b在模m意义下同余,记作 ab(modm)
对于整数x,y,m,如果 xy%m=1 ,称y是x模m的逆元。
求逆元

  • 解线性同余方程
    就是解 axb(modm) ,逆元为b=1的特殊情况
    方程可以转化为 ax+my=b ,应用ex-gcd可求。

  • 费马小定理
    对于一个素数p,及一个不是它的倍数的整数x,有
    xp11(modp)
    变形可得 xp21/x(modp)
    所以这种情况下 xp2 即为x的逆元
    应用快速幂可求
    适用范围:p为素数,x不为p的倍数

  • 欧拉定理
    gcd(a,b)=1
    aφ(b)1(modb)
    其中 φ(b) 表示1到b里和b互质的数的个数。
    同理 aφ(b)1 为a的逆元
    应用快速幂及欧拉函数可求

  • 奇技淫巧
    求n以内阶乘逆元
    n((n!)1)=(n1)!1
    应用递推可以线性求

  • O(n) 预处理 1n(n<p) 的逆元
    先假设我们已经求出来了 1i1 的逆元 f()
    p=x×i+y(0<y<i)
    那么 x×i+y=0(modp)
    x×i=y(modp)
    同时除以 iy
    x×f(y)=f(i)(modp)
    f(i)=(p/i)f(p%i)(modp)
    代换负数
    f(i)=(pp/i)f(p%i)(modp)
    p为质数适用。

3.组合计数

组合数的求法,模p意义下

  • 组合公式+逆元

    n!逆元可以线性递推得到,在n,m不大的情况下可以预处理出所有阶乘和逆元,直接求出组合数。

  • Lucas定理
    A、B是非负整数,p是质数。AB写成p进制:

    A=a[n]a[n1]...a[0]
    B=b[n]b[n1]...b[0]

    则组合数 C(A,B) C(a[n],b[n])C(a[n1],b[n1])...C(a[0],b[0])%p 同余
    即: Lucas(n,m,p)=c(n%p,m%p)Lucas(n/p,m/p,p)
    应用于p较小但A,B较大的情况,将A,B降到 105 左右就可以应用逆元求组合数

4.欧拉函数

n的欧拉函数值

int euler_phi(int n){
    int m = (int) sqrt(n+0.5);
    int ans = n;
    for(int i = 2; i <= m; i++) if(n % i == 0){
        ans = ans / i * (i-1);
        while(n % i == 0) n /= i;
    }
    if(n > 1) ans = ans / n * (n-1);//还剩一个大质数 
    return ans;
}//φ(n) = n(1-1/p1)(1-1/p2)(1-1/p3)...(1-1/pk) 

1~n中所有数的欧拉phi函数值

void phi_table(int n, int *phi){
    for(int i = 2; i <= n; i++) phi[i] = 0;
    phi[1] = 1;
    for(int i = 2; i <= n; i++) if(!phi[i])
        for(int j = i; j <= n; j += i){
            if(!phi[j]) phi[j] = j;
            phi[j] = phi[j] / i * (i - 1);
        }
}//一遍筛质数一边利用质因子算phi 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值