1. 程式人生 > >數論板子大總結

數論板子大總結

函數 分享圖片 nlog 最大 個性 乘法 復雜度 += 方程

在這裏,將有迄今為止學過的所有數論。

1、素數篩——埃拉托斯特尼篩法

時間復雜度:O(nloglogn)
方法:用每個素數篩所有它的倍數
證明:略

    for (int i=2;i<=N;i++) is[i]=1;
    for (int i=2;i<=N;i++)
    if (is[i])
        for (int j=i*i;j<=2000;j+=i)
        is[j]=0;

2、素數篩——歐拉篩法

時間復雜度:O(n)
方法&證明:埃拉托斯特尼對於每個合數篩了很多遍,而歐拉對於每個合數只被自己的最小質因數所篩去

    memset(is,1
,sizeof(is)); for (int i=2;i<=100000;i++) { if (is[i]) prime[++cnt]=i; for (int j=1;j<=cnt && i*prime[j]<=100000;j++) { is[i*prime[j]]=0; if (i%prime[j]==0) break; } }

3、歐拉函數

求[2,n)中與n互質的數的個數
//歐拉函數記做$\Phi(n)$
性質:
$\Phi(n)=\Phi(P_1^{a_1})\Phi(P_2^{a_2})\Phi(P_3^{a_3})…\Phi(P_s^{a_s})$
P為n的質因數,在n中a為其質因數的冪
定理:
(1)如果p是素數,那麽$\Phi(p)=p-1$ (逆定理成立)
(2)如果p是素數,那麽$\Phi(p^a)=p^a-p^{a-1}$
(3)設n和m互質,$\Phi(nm)=\Phi(n)\Phi(m)$
(4)p為n的質因數,a為對應指數,$\Phi(n)=n(1-1/p_1)(1-1/p_2)(1-1/p_3)…(1-1/p_s)$
推論:當n為奇數時,$\Phi(2

n)=\Phi(n)$
(5)設n>2,那麽$\Phi(n)$是偶數
(6)設n為正整數,$\sum_{d|n} \phi(d) = n$

//求一個數的歐拉函數
ll phi(ll x)
{
    ll ans=x,c=x;
    for (int i=2;i<=c/i;i++)
    {
    if (c%i==0) ans=ans/i*(i-1);
    while(c%i==0) c/=i;
    }
    if (c>1) ans=ans/c*(c-1);
    return ans;
}
//求[1,n]的歐拉函數
void euler(ll n)
{
    ll cnt=0
; memset(is,1,sizeof(is)); is[1]=0; for (ll i=2;i<=n;i++) { if (is[i]) prime[++cnt]=i,phi[i]=i-1; for (int j=1;j<=cnt && prime[j]*i<=n;j++) { is[prime[j]*i]=0; if (i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j]; break; } phi[i*prime[j]]=phi[i]*(prime[j]-1); } } }

4、歐拉定理&費馬小定理&乘法逆元

歐拉定理:對於任何兩個互質的正整數a和m(m>1),有$a^{\Phi(m)}\equiv1(mod m)$
費馬小定理:當m是質數時,$a^{m-1}\equiv1(mod m)$

5、歐幾裏得算法

//求a和b的最大公因數,記做gcd(a,b)
//(最小公倍數記做lcm(a,b),顯然lcm(a,b)=a*b/gcd(a,b))
又名輾轉相除法
原理:gcd(a,b)=gcd(b,a%b)
(詳情請參見更相減損術)

6、擴展歐幾裏得算法

求解ax+by=gca(a,b)的x和y
顯然這是一個不定方程,所以有多組解,而ex_gcd可以得出其中一組解,然後我們可以通過轉換求出所有解
證明:
技術分享圖片
因為$ax+by=1$ $→$ $ax+by+ab-ab=1$ $→$ $a(x+b)+b(y+a)=1$
所以在求出一個可行解x之後,不斷的把x+-b仍是該方程的一個解,利用這個性質可以求類似最小解的問題

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

7、中國剩余定理

emm…證明太繁瑣,附上百度百科的網址把
qwq

int CRT(int a[],int m[],int n)
{
    int M=1;
    int ans=0;
    for (int i=1;i<=n;i++)
    M*=m[i];
    for (int i=1;i<=n;i++)
    {
    int x,y;
    int Mi=M/m[i];
    exgcd(Mi,m[i],x,y);
    ans=(ans+Mi*x*a[i])%M;
    }
    if (ans<0) ans+=M;
    return ans;
}

數論板子大總結