1. 程式人生 > >【數論初步】

【數論初步】

一、歐幾里得 (連結)

1.歐幾里得演算法

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

2.擴充套件歐幾里得演算法

    //先得到更底層的x2,y2,再根據計算好的x2,y2計算x1,y1。
    //推理2,遞推關係
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b)
    {
        x=1;y=0;
        return a;
    }
    LL ret=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return ret;
}

3.貝祖等式

d0 是 ab 的最大公約數。
在方程ax+by=m中,如果 m=m0d0,那麼方程顯然有無窮多個解:

這裡寫圖片描述

(X0和Y0為擴充套件歐幾里得求出來的特解)

4.擴歐的乘法逆元

【逆元】設我們要求a/b%p的值,我們可以轉化為a*x%p。顯然,(1/b)%p=x%p,x*b%p=1。

前提:gcd(x,b)=1.這樣的話,x就存在。

如何求解a*x%n=1的方程呢?我們可以化成ax+ny=1,然後在上述gcd中帶出。(逆元:x=(x%p+p)%p;)

二、素數連結

1.尤拉函式

對正整數n,尤拉函式是小於或者等於n的數中與n互質的數的個數.

    

2.埃氏篩選(O(n*logn*logn))

const int N = 1e+6 + 7;
int pri[N],cnt;
bool isp[N];
void init_pri()
{
    for(int i=2; i<N; i++)
        if(!isp[i])
        {
            pri[++cnt]=i;
            for(int j=i+i;j<N;j+=i)isp[j]=true;
        }
}

3.尤拉篩選(O(n))

void init_pri(int n)
{
    cnt=0;
    for(int i=2; i<=n; i++)
    {
        if(!isp[i])
            pri[++cnt]=i;
        for(int j=1; j<cnt; j++)
        {
            long long k=1LL*i*pri[j];
            if(k>n)break;
            isp[k]=true;
            if(i%pri[j]==0)break;
        }
    }
} 

4.Miller Rabbin(判斷大素數)

# define ll long long
ll mypow(ll a,ll b,ll m)
{
    if(b==0)
        return 1;
    if(b==1)
        return a%m;
    ll temp=mypow(a,b/2,m);
    temp*=temp;
    temp%=m;
    if(b&1)
        temp*=a;
    temp%=m;
    return temp;
}
bool Miller_Rabbin(ll x)
{
    if(x==2)
        return true;        ///2要直接判斷
    for(int i=1;i<=50;++i){
        ll a=rand()%(x-2)+2;
        if(mypow(a,x-1,x)!=1)
            return false;
    }
    return true;
}
int main()
{
    ll n;
    while(scanf("%lld",&n)!=EOF)
    {
        if(Miller_Rabbin(n))
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
    return 0;
}

三、逆元 (連結)

  1.費馬小定理:假如p是質數,且gcd(a,p)=1,那麼 a(p-1)≡1(mod p)。即:假如a是整數,p是質數,且a,p互質(即兩數只有一個公約數1),那麼a的(p-1)次方除以p的餘數恆等於1。當膜P為素數時有a^(p-1)=1(mod p) 那麼a^(p-2)=a^-1(mod p)

也就是說a的逆元為a^(p-2)。一般P較大時用快速冪求逆元。

typedef  long long ll;
ll pow_mod(ll x, ll n, ll MOD)
{
    ll ret=1;
    while(n>0)
    {
        if(n&1)ret=ret*x%MOD;
        x=x*x%MOD;
        n>>=1;
    }
    return ret;
} 

  2.逆元打表

typedef  long long LL;  
const int N = 1e5 + 5;  
int inv[N];  
   
void inverse(int n, int p) {  
    inv[1] = 1;  
    for (int i=2; i<=n; ++i) {  
        inv[i] = (MOD - MOD / i) * inv[MOD%i] % MOD;  
    }  
}  

四、中國剩餘定理連結

1.當m1,m2,m3互質時

typedef long long LL;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b)
    {
        x=1;y=0;
        return a;
    }
    LL ret=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return ret;
}
LL CRT(LL a[],LL m[],int n)   /*模數為m,餘數為a x%m=a */
{
    LL M=1,ans=0;
    for(int i=1;i<=n;i++)M*=m[i];
    for(int i=1;i<=n;i++)
    {
        LL x,y;
        LL Mi=M/m[i];
        exgcd(Mi,m[i],x,y);
        ans=(ans+Mi*x*a[i])%M;
    }
    if(ans<0)ans+=M;
    return ans;
}

2.線性同餘方程

typedef long long LL;
LL a[N],m[N]; /*模數為m,餘數為a x%m=a */
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b)
    {
        x=1,y=0;
        return a;
    }
    LL ret=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return ret;
}
bool solve(LL &m0,LL &a0,LL m,LL a)
{
    LL x,y;
    LL gcd=exgcd(m0,m,x,y);
    if((a-a0)%gcd)return false;
    x*=(a-a0)/gcd;
    x%=m/gcd;
    a0=a0+x*m0;
    m0*=m/gcd;
    a0=(a0%m0+m0)%m0;
    return true;
}
bool MLES(LL &m0,LL &a0,int n)  /* 有解返回true,並且x=a0+k*m*/
{
    bool flag=true;
    m0=1;a0=0;
    for(int i=1;i<=n;i++)
    if(!solve(m0,a0,m[i],a[i]))
    {
        return false;
    }
    return true;
}