ACM算法总结 数论(一)

目录

        • 快速幂
        • 龟速乘
        • 费马小定理
        • 欧拉函数
        • 欧拉定理
        • 扩展欧拉定理
        • 素性测试
        • 裴蜀定理&扩展欧几里得
        • 逆元
          • 线性求n个数的逆元
          • 线性求任意n个数的逆元
        • 中国剩余定理(CRT)



快速幂

int ksm(int x,int n,int M)
{
	//if(!x && !n) return 0;
    int ret=1;
    while(n)
    {
        if(n&1) ret=1ll*ret*x%M;
        x=1ll*x*x%M;
        n>>=1;
    }
    return ret;
}

这里要特别注意 0 的 0 次方是没有意义的,按照任何数的零次方等于 1 的定义1,0 的 0 次方等于 1,但是不管多少个 0 相乘却又等于 0 。所以这里要具体情境具体调整。



龟速乘

用来处理大整数(long long 类型)的乘法取模问题,因为两个 long long 相乘可能精度会不够,所以就用 logn 的方法来做乘法。

LL multi(LL x,LL y,LL M)
{
    LL ret=0;
    while(y)
    {
        if(y&1) ret=(ret+x)%M;
        x=(x<<1)%M;
        y>>=1;
    }
    return ret;
}



费马小定理

p p p为素数, g c d ( a , p ) = 1 gcd(a,p)=1 gcd(a,p)=1,则 a p − 1 ≡ 1   ( m o d   p ) a^{p-1} \equiv 1 \ (mod \ p) ap11 (mod p)



欧拉函数

φ ( x ) \varphi(x) φ(x)为欧拉函数,代表小于等于 x x x且与 x x x互质的数的个数。

  • 欧拉函数是积性函数,即对于 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1,有 φ ( a b ) = φ ( a ) φ ( b ) \varphi(ab)=\varphi(a)\varphi(b) φ(ab)=φ(a)φ(b)

  • n = ∑ d ∣ n φ ( d ) n=\sum_{d|n}\varphi(d) n=dnφ(d)

  • 利用唯一分解定理,设 x = p 1 k 1 p 2 k 2 . . . p s k s x=p_1^{k_1}p_2^{k_2}...p_s^{k_s} x=p1k1p2k2...psks,则 φ ( x ) = x × ∏ i = 1 s ( 1 − 1 p i ) \varphi(x)=x\times\prod_{i=1}^{s}{(1-\frac{1}{p_i})} φ(x)=x×i=1s(1pi1)

直接求:

int phi(int n)
{
    int ans=n;
    for(int i=2;i*i<=n;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;
}

打表:

const int maxn=1e7+5;
int phi[maxn];

void euler_table(int n)
{
    for(int i=0;i<=n;i++) phi[i]=i;
    for(int i=2;i<=n;i++)
        if(phi[i]==i)
            for(int j=i;j<=n;j+=i)
                phi[j]=phi[j]/i*(i-1);
}



欧拉定理

g c d ( a , m ) = 1 gcd(a,m)=1 gcd(a,m)=1,则 a φ ( m ) ≡ 1   ( m o d   m ) a^{\varphi(m)}\equiv 1 \ (mod \ m) aφ(m)1 (mod m)



扩展欧拉定理

a b ≡ { a b   m o d   φ ( p ) , g c d ( a , p ) = 1 a b , g c d ( a , p ) ≠ 1 ,   b < φ ( p ) ( m o d   p ) a b   m o d   φ ( p )   + φ ( p ) , g c d ( a , p ) ≠ 1 ,   b ≥ φ ( p ) a^b \equiv \left\{ \begin{array}{lr} a^{b \ mod \ \varphi(p)} ,& gcd(a,p)=1 & \\ a^b ,& gcd(a,p)\neq 1, \ b < \varphi(p) & \qquad (mod \ p) \\ a^{b \ mod \ \varphi(p) \ +\varphi(p)}, & gcd(a,p) \neq 1, \ b \geq \varphi(p) \end{array} \right. abab mod φ(p),ab,ab mod φ(p) +φ(p),gcd(a,p)=1gcd(a,p)=1, b<φ(p)gcd(a,p)=1, bφ(p)(mod p)



素性测试

Fermat素性测试,单个数,int范围内,O(logn):

bool is_prime(int x)
{
    if(x==1) return 0;
    if(x==2 || x==3 || x==5 || x==7) return 1;
    if(ksm(2,x-1,x)!=1) return 0;
    if(ksm(3,x-1,x)!=1) return 0;
    if(ksm(5,x-1,x)!=1) return 0;
    if(ksm(7,x-1,x)!=1) return 0;
    return 1;
}

素数表,Eratosthenes筛法(埃拉托斯特尼筛法),O(nloglogn):

const int maxn=1e7+5;
bool is_prime[maxn];

void prime_table(int n)
{
    for(int i=2;i<=n;i++) is_prime[i]=1;
    for(int i=2;i*i<=n;i++)
        if(is_prime[i])
            for(int j=i*i;j<=n;j+=i)
                is_prime[j]=0;
}



裴蜀定理&扩展欧几里得

扩展欧几里得算法用于求解 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b),核心公式是 a x 1 + b y 1 = a y 2 + b ( x 2 − ⌊ a b ⌋ y 2 ) ax_1+by_1=ay_2+b(x_2- \lfloor \frac{a}{b} \rfloor y_2) ax1+by1=ay2+b(x2bay2)

返回值为 g c d ( a , b ) gcd(a,b) gcd(a,b)

LL ex_gcd(LL a,LL b,LL &x,LL &y)
{
    if(!b) {x=1; y=0; return a;}
    LL r=ex_gcd(b,a%b,x,y),t=x;
    x=y,y=t-a/b*y;
    return r;
}

那么怎么保证一定有解呢?这个要涉及到裴蜀定理(贝祖定理):

  • a , b a,b a,b是不全为零的整数,则存在整数 x , y x,y x,y,使得 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)

一个推论: a , b a,b a,b互质当且仅当 a x + b y = 1 ax+by=1 ax+by=1 有解。

扩展欧几里得算法可以应用到很多地方,比如求解线性同余方程。



逆元

线性同余方程 a x ≡ 1 ( m o d   p ) ax \equiv 1 (mod \ p) ax1(mod p) 的解 x x x 称为 a   m o d   p a \ mod \ p a mod p 意义下的逆元。

假设 p p p 为质数并且 a 和 p 互质,那么可以用费马小定理来求解:

  • 费马小定理: x ≡ a p − 2 ( m o d   p ) x \equiv a^{p-2} (mod \ p) xap2(mod p) ,然后调用快速幂 k s m ( a , p − 2 , p ) ksm(a,p-2,p) ksm(a,p2,p) 即可;

    int inv(int a,int p)
    {
    	return ksm(a,p-2,p);
    }
    

假设 p p p 不是质数但 a , p a,p a,p 互质,那么可以用欧拉定理求解`;

int inv(int a,int p)
{
	return ksm(a,phi(p)-1,p);
}

只要 a , p a,p a,p互质,就可以用扩展欧几里得来求解:

  • 扩展欧几里得: a x + p y = 1 ax+py=1 ax+py=1 的解 x x x 即为 a a a 的逆元(a、p互质,模p为1)。

    LL inv(LL a,LL p)
    {
    	LL x,y;
    	ex_gcd(a,p,x,y);
    	return (x+p)%p;
    }
    

假设 g c d ( a , p ) > 1 gcd(a,p)>1 gcd(a,p)>1 那么逆元不存在(!)

线性求n个数的逆元

核心公式为 x − 1 ≡ − ⌊ p x ⌋ ( p % x ) − 1 ( m o d   p ) x^{-1} \equiv - \lfloor\frac{p}{x}\rfloor(p\%x)^{-1}(mod \ p) x1xp(p%x)1(mod p) ,代码如下:

const int maxn=1e6+5;
int inv[maxn];

void get_inv(int n,int M)
{
	inv[1]=1;
	REP(i,2,n) inv[i]=1ll*inv[M%i]*(M-M/i)%M;
}
线性求任意n个数的逆元

设这n个数为 a i a_i ai ,首先计算其前缀积 s i s_i si ,那么就可以倒着递推出每个 s i s_i si 的逆元 s v i = s v i + 1 a i + 1 sv_i=sv_{i+1}a_{i+1} svi=svi+1ai+1 ,最后 a i a_i ai 的逆元就等于 s v i s i − 1 sv_is_{i-1} svisi1



中国剩余定理(CRT)

就是计算这样一个问题:有一个数,它模 a 1 a_1 a1 m 1 m_1 m1 ,模 a 2 a_2 a2 m 2 m_2 m2 ,……,模 a n a_n an m n m_n mn ,要求这个数的最小值。

中国剩余定理可以很好地解决这个问题。

模数两两互质:

LL CRT(LL n,LL *m,LL *a)
{
    LL M=1,ans=0,x,y;
    for(int i=1;i<=n;i++) M*=m[i];
    for(int i=1;i<=n;i++)
    {
        LL mi=M/m[i];
        ex_gcd(mi,m[i],x,y);
        x=(x%m[i]+m[i])%m[i];   //最小非负解
        ans=(ans+mi*x*a[i])%M;
    }
    return (ans+M)%M;
}

任意模数:

LL ex_CRT(int n,LL *m,LL *a)     //扩展中国剩余定理
{
    LL x,y,k,M=m[1],ans=a[1];
    for(int i=2;i<=n;i++)
    {
        LL c=(a[i]-ans%m[i]+m[i])%m[i];
        LL t=ex_gcd(M,m[i],x,y),bg=m[i]/t;
        if(c%t) return -1;
        x=c/t*x%bg;     //x可能是负的
        ans+=x*M;
        M*=bg;
        ans=(ans%M+M)%M;
    }
    return (ans%M+M)%M;
}

其中,m为模数数组,a为余数数组。

有时候某些数论题的模数不是质数,但是其质因子不重复,就可以分别对质因子运算然后CRT合并答案。

你可能感兴趣的:(ACM算法总结)