復習:數論


質數

判斷質數

朴素算法

考慮一個數\(x\),其一定能分解成\(a*b\)的形式,這里只需要保證\(a\)\(b\)都為整數即可,

顯然的,\(min(a,b)\le \sqrt{x}\),所以只需要枚舉\([2,\sqrt x]\)即可

bool pd(int x)
{
    for(int i=2;i*i<=x;i++)
        if(x%i==0)
            return 0;
    return 1;
}

Miller_Rabin素性測試

內容

首先根據費馬定理

隨便取一個數\(a\)

如果\(p\)為質數,那么就有\(a^{p-1}\equiv 1 \pmod p\),但是反過來不成立

具體的,卡邁克爾數

所以我們需要用到二次探測方法

我們將\(p-1\)分解成為\(2^r*k\),保證有\(2\not| \frac{p-1}{2^r}\),則有\(a^{p-1}=a^{{k}^{2r}}\)

先求出\(a^k\),再不斷平方,如果第一次模\(p\)的值為1,那么檢測上一次的值是否為\(-1\),如果是那么就是質數

考慮如果有\(y^2\%p=1\)

那么就有\((y-1)(y+1)=kp\)

如果\(p\)為質數,那么一定有

\(y-1=0或者y+1=p\)

所以\(y\)的值只能是\(1\)或者\(p- 1\)

考慮如果有\(r\)次平方之后依然沒有出現余數為\(1\)的情況,那么顯然\(p\)不為質數

但是通過二次探測,我們依然不能百分之百的確定\(p\)是不是質數,但是出錯的概率非常小,基於此,如果多來幾次,則可以接近百分之百的概率了

這里建議\(a\)選擇質數

實現

bool f=1;
for(int i=1;i<=lenp;i++)
{  
	if(mod%pri[i]==0)
		continue;
    if(qkpow(pri[i],mod-1,mod)!=1&&pri[i]%mod!=0)
    {
        f=0;
        break;
    }
    int cnt=0;
    long long t=mod-1;
    while(t%2==0)
    {
        t/=2;
        cnt++;
    }
    long long now=qkpow(pri[i],t,mod);
    long long las=now;
    if(now==1)
    	continue;
    for(int j=1;j<=cnt;j++)
    {
        now=qkpow(now,2,mod);
        if(now==1)
        {
            if(las!=mod-1)
                f=0;
            break;
        }
        las=now;
    } 
    if(now!=1)
    	f=0;
}
if(f)
    cout<<"It is a prime number.\n";
else
    cout<<"It is not a prime number.\n";

區間內的質數

埃氏篩法

一個自然數集合

考慮到質數的因數只有\(1\)和他本身,所以考慮對每一個數,將其在集合中的所有的倍數都刪去,沒有被刪去的數即為質數,時間復雜度即為\(\sum_{i=1}^{n}\frac{n}{i}=n*log_n\)(調和級數求和),也可以看做每個數被篩了多少次

bool vis[MAXN+5];
int pri[MAXN],lenp;
void sieve(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(vis[i]==0)
        {
            pri[++lenp]=i;
            for(int j=i;1ll*i*j<=n;j++)
                vis[i*j]=1;
        }
    }
}

歐拉篩

考慮在埃氏篩上進行改進,為什么埃氏篩會帶一個log,因為其會被其所有的質因數都篩一次

我們對其進行一些限制,每一個數只能被其最小的質因數篩去

考慮目前的質數集合為\(P\),我們枚舉其的倍數\(a\)

從小到大枚舉\(P\)中的元素

如果\(a\%p_i==0\),那么比\(p_i\)大的元素可以不用枚舉,設\(a=k*p_i\),那么\(a*p_{i+1}=p_i*k*p_{i+1}\),根據我們所規定的限制,那么\(a*p_{i+1}\)一定會被\(p_i\)篩去,

bool vis[MAXN+5];
int pri[MAXN],lenp;
void sieve(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(vis[i]==0)
            pri[++lenp]=i;
        for(int j=1;j<=lenp&&1ll*i*pri[j]<=n;j++)
        {
            vis[i*pri[j]]=1;
            if(i%pri[j]==0)
                break;
        }
    }
}

最大公約數和最小公倍數

輾轉相除法

內容

\(gcd(a,b)=gcd(b,a\%b)\)

證明

\(gcd(a,b)=p\),那么\(\begin{cases}a=x*p\\b=y*p\end{cases}\)\(a\%b=(x*p)\%(y*p)=x\%y*p\)

\(b\)\(a\%b\)的最大公約數依然為\(p\)

實現

其實可以直接用\(algorithm\)庫中的__gcd

int gcd(int a,int b)
{
    if(b==0)
        return a;
    return gcd(b,a%b); 
}

裴蜀定理

內容

如果有\(gcd(a,b)=d\),且有\(c|d\),那么一定有整數\(x,y\),滿足\(ax+by=c\)

證明

如果有\(ax+by=c\),那么一定有\(ax*\frac{d}{c}+by*\frac{d}{c}=d\),設\(x'=x*\frac{d}{c},y'=y*\frac{d}{c}\),此時的\(x'和y'\)一定都為整數,那么\(ax'+by'=d\),因為\(gcd(a,b)=d\),所以有\(\frac{a}{d}x'+\frac{b}{d}y'=1\)。同樣的,設\(a'=\frac{a}{d},b'=\frac{b}{d}\),所以\(a'x'+b'y'=1\)

我們要證明的既可以轉換為:對於一對\(a,b\),滿足\(gcd(a,b)=1\),一定有整數\(x,y\),滿足\(ax+by=1\)

引理1

如果有\(gcd(a,b)=1\),那么不存在一個小於b的正整數k,使得\(k*a\equiv 0\pmod b\)

反證法,

如果存在一個\(k\)使得\(k*a\equiv 0 \pmod b\),那么\(k*a\)中一定有\(b\)的所有質因數,但同時\(a\)沒有任何一個\(b\)的質因數,所以\(k\)一定包含\(b\)的所有質因數,即\(k\ge b\),矛盾,所以引理得證

推論

在相同的條件下,\(0*a\%b,1*a\%b\ldots(b-1)*a\%b\),這些數一定都不一樣

反證法,

\(i*a\equiv j*a\pmod b,同時0<i<j<b\),那么一定有\(a*(j-i)\equiv 0 \pmod b\)

根據引理1,\(j-i\ge b\),顯然這是矛盾的

引理2

如果有\(gcd(a,b)=1\),必然存在一個整數\(k\),使得\(k*a\%b=1\)

根據推論,對於\(0*a\%b,1*a\%b\ldots(b-1)*a\%b\),這些數一定不一樣,但是某一個數取模\(b\)的結果一定在\([0,b-1]\),但是同時根據推論,我們已經可以得到\(b\)個兩兩不相同的數,所以k一定存在

再來考慮如果有\(gcd(a,b)=1\),那么一定有\(x*a\%b=1\),所以定然有\(ax-by=1\),所以有\(ax+by=1\),即裴蜀定理得證

同余等價系,剩余系,縮系

對於一個正整數\(p\),對於\(a\%p\),只可能有\(p\)種結果,並且屬於\([0,p-1]\)

\(p\)的剩余系記作\(Z_p\),即小於\(p\)的所有非負整數

同余等價類,

考慮在模\(p\)的剩余系下,只有\(p\)種結果,所以每一個數都代表了\(\%p=a\)的所有數,對於\(a\)相同的數,我們稱其為同余等價類

如果只考慮\(gcd(i,p)=1\)的元素,便得到一個子集,稱這個子集為縮系,記作\(Z^*_p\)

歐拉函數

內容

\(p\)得縮系的大小,記作\(\phi(p)\)

如果\(p\)為質數,那么\(\phi(p)=p-1\)

如果\(n=p^q\),這里的\(p\)為質數,那么\(\phi(n)=p^q-p^{q-1}=p^q*(1-\frac{1}{p})\)

同時歐拉函數是一個積性函數證明

所以\(\phi(n)=n*\prod_{p_i|n,並且p_i為質數}(1-\frac{1}{p_i})\)

求單個\(\phi\)

直接套用公式即可

int phi(int n)
{
    int ret=n;
    for(int i=2;1ll*i*i<=n;i++)
    {
        if(n%i==0)
        {
            ret=ret/i*(i-1);
            while(n%i==0)
                n=n/i;
        }
    }
    if(n>1)
        ret=ret/n*(n-1);
    return ret;
}

求區間每個數的\(\phi\)

因為\(\phi\)為積性函數,所以只需要改進一下埃氏篩法即可,

當然也可以改歐拉篩,但是改后的時間復雜度變成了\(O(n*log_n)\)可能是筆者太菜,想不到更好的改法

void sieve(int n)
{
    for(int i=1;i<=n;i++)
        s[i]=i;
    for(int i=2;i<=n;i++)
    {
        if(vis[i]==0)
        {
            for(int j=1;1ll*i*j<=n;j++)
            {
                vis[i*j]=1;
                s[i*j]=s[i*j]/i*(i-1);
            }
        }
    }
}

歐拉定理

內容

如果有\(gcd(a,p)=1\),那么有\(a^{\phi(p)}\%p=1\)

證明

\(p\)的縮系為\(\{p_1,p_2,\ldots,p_n\}\),因為\(gcd(a,p)=1\),所以\(\{a*p_1\%p,a*p_2\%p,\ldots,a*p_n\%p\}\)同樣也是\(p\)的縮系

所以有\(\sum_{i=1}^{n}p_i\%p=\sum_{i=1}^{n}a*p_i\%p=\sum_{i=1}^{n}p_i\%p*a^{\phi(p)}\%p\)

\(a^{\phi(p)}\%p=1\)

拓展歐拉定理

內容

\(a,m\)為正整數,當\(r>\phi(m)\),有\(a^r\equiv a^{r\%\phi(m)+\phi(m)}\pmod m\)

證明

考慮如果\(gcd(a,m)=1\),這個結論顯然成立

所以討論\(gcd(a,m)\neq1\)的情況

引理1

如果有\(\begin{cases}x\equiv y\pmod n\\x\equiv y\pmod m\end{cases}\),那么有\(x\equiv y \pmod {lcm(n,m)}\)

比較明顯?

\(\begin{cases}x-y\equiv 0\pmod n\\x-y\equiv 0 \pmod m\end{cases}\rightarrow x-y\equiv 0 \pmod {lcm(n,m)}\rightarrow x\equiv y \pmod {lcm(n,m)}\)

引理2

如果\(p\)為質數,\(\phi(p^q)\ge q\)

顯然的\(gcd(p^i-1,p^1)==1\),並且\(i\in [1,q]\),所以\(\phi(p^q)\ge q\)

引理3

如果\(m=p^q\)\(p\)為質數,那么有\(a^r\equiv a^{r\%\phi(m)+\phi(m)}\equiv 0\pmod m\)

因為\((a,m)>1\),則\(a\)必然有因數\(p\)

因為\(r>\phi(m)\ge q\),所以有\(a^r=x*p^r=y*p^{\phi(m)}=z*p^{q}\)

因為\(r>q\),所以\(a^r\equiv 0 \pmod m\)

因為\(\phi(m)\ge q\),所以\(r\%\phi(m)+\phi(m)\ge q\),所以\(a^{r\%\phi(m)+\phi(m)}\equiv 0\pmod m\)

所以\(a^r\equiv a^{r\%\phi(m)+\phi(m)}\equiv 0\pmod m\)

現在考慮\(m=\prod p_i^{q_i}\)

\(m_i=p_i^{q_i}\)

顯然,對於每一個\(m_i\)

如果\(gcd(a,m_i)=1\),則根據歐拉定理可以得到\(a^r\equiv a^{r\%\phi(m)+\phi(m)}\pmod {m_i}\)

如果\(gcd(a,m_i)>1\),則根據引理3有\(a^r\equiv a^{r\%\phi(m)+\phi(m)}\pmod {m_i}\)

因為歐拉函數是一個積性函數並且\(m_i\)之間兩兩互質,所以\(\phi(m)=\prod \phi(m_i)\)

根據引理1可以得

\(a^r\equiv a^{r\%\phi(m)+\phi(m)}\pmod m\)

逆元

當整數\(a*b\equiv 1 \pmod p\),我們稱\(b\)為a的逆元,記作\(b=a^{-1}\)

只有\(a\)\(p\)互質的情況下,\(a\)才有逆元

費馬定理

內容

如果\(p\)為質數,且\(a\%p\neq 0\),則有\(a^{p-1}\%p=1\)

證明

考慮到裴蜀定理的推論,對於\(i\in[1,p-1]\)\(gcd(i*a,p)\)一定是互質的,

即有\(\sum_{i=1}^{p-1}i*a\%p=\sum_{i=1}^{p-1}i\%p\)

又知道\(\sum_{i=1}^{p-1}i*a\%p=a^{p-1}\%p*\sum_{i=1}^{p-1}i\%p\)

即有\(a^{p-1}\%p=1\)

威爾遜定理

內容

\((p-1)!\equiv -1\pmod p\),當且僅當\(p\)為質數,其中\((p-1)!=\prod_{i=1}^{p-1}i\)

證明

充分性

\(p\)為質數\(\rightarrow (p-1)!\equiv -1 \pmod p\)

因為\(i\in [1,p-1]\),且\(p\)為質數,所以一定有\(gcd(i,p)=1\),根據裴蜀定理的引理2,一定存在\(j*a\%p=1\)\(j\in[1,p-1]\),同時,根據裴蜀定理的引理1,\(i\)只有1個逆元,

再者,我們考慮\(j=i\)的情況

\(i^2\%p=1\rightarrow i^2-1=kp\)

\((i-1)(i+1)=kp\),同時\(p\)為質數,且\(i\in[1,p-1]\)

\(i=1,p-1\)

即除了1和p-1,其他數都有一個唯一的逆元,同時我們根據歐拉定理$a^{-1}\equiv a^{p-2}\pmod p $,再根據裴蜀定理的引理1,每個數的逆元都是不一樣的(反證法)

所以一定有$(p-1)!\equiv -1 \pmod p $

必要性

\((p-1)!\equiv -1 \pmod p \rightarrow\) \(p\)為質數

\(p|(p-1)!+1\)

假設\(p\)不是質數,且\(a\)\(p\)的質因子

那么一定有\(a|(p-1)!+1\)

但是同時,因為\(a\)\(p\)的一個質因子,所以一定有\(a|(p-1)!\)

但同時\(gcd((p-1)!+1,(p-1)!)=1\),故\(a\)只可能為1,

與假設矛盾,所以不成立,即命題得證

拓展歐幾里得

內容

求不定方程\(ax+by=c\),其中\(a,b,c\)已知,\(gcd(a,b)|c\)

如果我們已知方程\(ax+by=gcd(a,b)\),那么\(ax+by=c\)也就是在原來的基礎上乘上\(\frac{c}{gcd(a,b)}\)

\(\begin{aligned}ax+by&=gcd(a,b)\\&=gcd(b,a\%b)\\&=bx'+(a\%b)y'\\&=bx'+(a-b*\lfloor\frac{a}{b}\rfloor)y'\\&=ay'+b(x'-y'\lfloor\frac{a}{b}\rfloor)\end{aligned}\)

\(\begin{cases}x=y'\\y=x'-y'\lfloor\frac{a}{b}\rfloor\end{cases}\)

考慮一直遞歸下去,則一定會出現\(gcd(a,0)=a\)的情況

即此時\(\begin{cases}x=1\\y=0\end{cases}\)

實現

void exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return;
    }
    else
    {
        exgcd(b,a%b,y,x);
        y=y-x*(a/b);
    }
}

單個逆元

費馬

內容

\(p\)為質數的情況下

根據費馬定理\(a^{p-1}\equiv 1\pmod p\),所以\(a^{p-2}\equiv a^{-1}\pmod p\)

如果\(p\)不是質數

考慮對\(ax\%p=1\),那么就一定有\(ax-py=1\),設\(y'=-y\),則有\(ax+py'=1\)

這里因為\(a\)\(p\)互質,所以方程一定有解,通過拓展歐幾里得算法即可求出\(x\)

實現

不會有人連快速冪都不會吧,不會吧不會吧

int qkpow(int a,int b)
{
    if(b==0)
        return 1;
    if(b==1)
        return a;
    long long t=qkpow(a,b/2);
    t=t*t%mod;
    if(b%2==1)
        t=t*a%mod;
    return t;
}

拓展歐幾里得

內容

顯然的,有方程\(ia\equiv 1 \pmod p\)

考慮對方程進行變形\(ia -1=jp\)

\(ia-jp=1\)

這個時候直接用exgcd來解就可以了

實現

void exgcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return;
    }
    else
    {
        exgcd(b,a%b,y,x);
        y=y-x*(a/b);
    }
}
long long inv(long long a,long long b)
{
    long long x,y;
    exgcd(a,b,x,y);
    return (x%b+b)%b;
}

區間逆元

遞推式

關於逆元,有一個很巧妙的遞推式

\(f(i)\)表示\(i\)在模\(m\)意義下的逆元

邊界條件即為\(f(1)=1\)

那么\(f(n)=(-f(m\%n)*(m/n)\%m+m)\%m\)

證明

我們設\(m=k*i+r\)\(k=\lfloor\frac{p}{m}\rfloor,r=m\%n\)

那么\(k*i+r\equiv 0\pmod m\)

那么有\((k*i+r)*i^{-1}*r^{-1}\equiv 0*i^{-1}*r^{-1}\pmod m\)

\(k*r^{-1}+i^{-1}\equiv 0\pmod m\)

\(k*r^{-1}\equiv -i^{-1}\pmod m\)

\(-k*r^{-1}\equiv i^{-1}\pmod m\)

即遞推式得證

中國剩余定理

非拓展

內容

求解方程組\(\begin{cases}x\equiv a_1\pmod {r_1}\\x\equiv a_2\pmod {r_2}\\\dots\\x\equiv a_n\pmod {r_n}\end{cases}\)保證\(r_i\)兩兩互質

解法

我們設\(A_i=\prod_{j=1}^n r_j[i\neq j]\),因為\(r_i\)之間兩兩互質,所以\(gcd(A_i,r_i)=1\),所以必然存在\(c_i*A_i\%r_i=1\)(裴蜀定理的引理2),設\(x_i=a_i*A_i*c_i\),則\(x_i\%r_i=a_i\),且\(x_i\%r_j=0(i\neq j)\)

所以最后的\(x=\sum_{i=1}^{n}a_i*A_i*c_i\%r\)

通解的話就相當與\(x+\prod_{i=1}^nr_i\)

實現

long long crt()
{
    long long s=1,x=0;
    for(int i=1;i<=n;i++)
        s=s*r[i];
    for(int i=1;i<=n;i++)
        x=(x+(a[i]*(s/r[i])%s*inv(s/r[i],r[i]))%s)%s;
    return x;
}

拓展

內容

總有一些惡心的出題人,將\(r_i\)兩兩互質的條件刪去,但依然需要我們求解方程組\(\begin{cases}x\equiv a_1\pmod {r_1}\\x\equiv a_2\pmod {r_2}\\\dots\\x\equiv a_n\pmod {r_n}\end{cases}\)

解法

考慮取出前兩個方程,即有\(\begin{cases}x=r_1*k_1+a_1\\x=r_2*k_2+a_2\end{cases}\)

\(r_1*k_1+a_1=r_2*k_2+a_2\)

\(r_1*k_1-r_2*k_2=a_2-a_1\)

這是一個不定方程的形式,可以用exgcd來求解

其中\(k_1\)的通解為\(k_1=k_0+b*\frac{r_2}{gcd(r_1,r_2)}\)\(k_0\)為方程的一組特解

\(k_1\)代回去

\(x=(k_0+b*\frac{r_2}{gcd(r_1,r_2)})*r_1+a_1\)

\(x=k_0*r_1+b*lcm(r_1,r_2)+a_1\)

\(x\equiv k_0*r_1+a_1\pmod {lcm(r_1,r_2)}\)

發現這個方程與方程組中方程的形式的一樣的,並且滿足這一個方程一定也滿足取出來的兩個方程

所以最后實際上需要求解的是\(x\equiv a\pmod r\)的一個方程,這把\(x=a\)不就行了

實現

void exgcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return;
    }
    else
    {
        exgcd(b,a%b,y,x);
        y=y-x*(a/b);
    }
}
long long solve(long long a,long long b,long long c)
{
    long long x,y;
    exgcd(a,b,x,y);
    x=x*c/__gcd(a,b);
    x=x%(b/__gcd(a,b));
    return x;
}
long long excrt()
{
    long long mod;
    for(int i=2;i<=n;i++)
    {
        if((a[i]-a[i-1])%__gcd(r[i],r[i-1])!=0)
            return -1;
        mod=(r[i-1]*r[i])/__gcd(r[i-1],r[i]);
        a[i]=solve(r[i-1],r[i],a[i]-a[i-1])%mod*r[i-1]%mod+a[i-1];
        r[i]=mod;
        a[i]=(a[i]%r[i]+r[i])%r[i];
    }
    return a[n];
}

原根

如果有兩個整數\(a\)\(b\)互質,那么根據歐拉定理\(a^{\phi(b)}\%b=1\)

定義模\(b\)意義下\(a\)的階為使\(a^d\%b=1\)的最小正整數\(d\)

如果\(d=\phi(b)\),那么稱\(a\)\(b\)的原根

歐拉證明了,模\(b\)存在原根的充要條件為\(b=2,4,p^n,2p^n\),其中\(p\)為奇質數,\(n\)為任意正整數

原根的數量

如果\(b\)有原根的話,原根的數量為\(\phi(\phi(b))\)

求原根

沒有什么特別好的辦法,暴力枚舉每一個數是不是原根

對於一個數\(a\),如果存在\(a^{\frac{\phi(b)}{p}}\%b=1\),這里的\(p\)\(\phi(b)\)的質因數,則\(a\)不是原根,否則就不是

因為如果有一個數\(a^i\%b=1\),那么\(i|\phi(b)\),並且我們一定會枚舉到\(p\)使得\(i|\frac{\phi(b)}{p}\),只需要使得\(gcd(i,p)=1\)即可

大步小步算法(BSGS)

非拓展

內容

考慮有一個同余方程\(a^x\equiv b \pmod p\)\(a,b,p\)已知,\(p\)\(a\)互質,求解\(x\)

解法

我們設\(m=\lceil\sqrt p\rceil,r=x\%m\)

顯然的,我們有\(x=km+r\),其中\(k\in[0,\lceil\sqrt p\rceil-1],r\in[0,p-1]\)

\(a^{km+r}\equiv b\pmod p\)

同樣的,我們再次變化一下\(k\in[1,\lceil\sqrt p\rceil],r\in[1,m]\)

\(a^{km-r}\equiv b \pmod p\)

\(a^{km}\equiv ba^r\pmod p\)

我們只需要將\(ba^r\%p\)存在一個map中,再枚舉\(a^{km}\)即可

實現

long long bsgs(long long a,long long b,long long mod)
{
    long long m=ceil(sqrt(mod));
    long long temp=1;
    for(int i=1;i<=m;i++)
    {
    	temp=temp*a%mod;
      f[b*temp%mod]=i;
	}
	long long ret=temp;
    for(int i=1;i<=m;i++,ret=ret*temp%mod)
        if(f.count(ret))
            return i*m-f[ret];
    return -1;
}

拓展

內容

一樣的條件,只是單純的將\(a\)\(p\)互質這一點去掉

解法

考慮將式子進行變形,那么有\(a^x+kp=b\)

\(gcd(a,p)=g\),顯然\(g\not | b\)的時候,方程無解,

但是這里明顯有一個例外,當\(b=1\)的時候,\(x=0\)

那么有\(\frac{a}{g}a^{x-1}+k\frac{p}{g}=\frac{b}{g}\)

我們就這么一直迭代下去,設\(a'\)\(\frac{a}{g}\)的乘積,\(p'\)為最后的\(\frac{p}{g}\)\(b'\)為最后的\(\frac{b}{g}\)

假設迭代了\(cnt\)

那么最后的式子的形式是一定\(a^{x-cnt}a'+kp'=b'\)

即為\(a^{x-cnt}a'\equiv b'\pmod {p'}\rightarrow a^{x-cnt}\equiv b'a'^{-1}\pmod {p'}\)

與原式不同的是,這里保證\(gcd(a^{x-cnt},p')=1\)

所以此時就可以直接用非拓展的BSGS來做

顯然的,迭代最多迭代\(log\)次,所以總的時間復雜度依然為\(\sqrt n\)

實現

void exgcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return;
    }
    else
    {
        exgcd(b,a%b,y,x);
        y=y-x*(a/b);
    }
}
long long inv(long long a,long long b)
{
    long long x,y;
    exgcd(a,b,x,y);
    return (x%b+b)%b;
}
long long bsgs(long long a,long long b,long long mod)
{
    f.clear();
    long long m=ceil(sqrt(mod)),temp=1;
    for(int i=1;i<=m;i++)
    {
        temp=temp*a%mod;
        f[temp*b%mod]=i;
    }
    long long ret=temp;
    for(int i=1;i<=m;i++,ret=ret*temp%mod)
        if(f.count(ret))
            return i*m-f[ret];
    return -1;
}
long long exbsgs(long long a,long long b,long long mod)
{
    int cnt=0;
    long long g;
    while(__gcd(a,mod)!=1)
    {
        g=__gcd(a,mod);
        if(b%g!=0)
        {
            if(b==1)
                return cnt;
            else
                return -1;
        }
        cnt++;
        b/=g;
        mod/=g;
        b=b*inv(a/g,mod)%mod;
        if(b==1)
            return cnt;
    }
    return cnt+bsgs(a,b,mod);
}

高斯消元

內容

求解線性方程組\(\begin{cases}i_{11}x_1+i_{12}x_2+\dots+i_{1n}x_n=a_1\\i_{21}x_1+i_{22}x_2+\dots+i_{2n}x_n=a_2\\\dots\\i_{n1}x_1+i_{n2}x_2+\dots+i_{nn}x_n=a_n\end{cases}\)

解法

很明顯的有一個暴力的方法,但是這個暴力的方法對於人類來說十分的不方便

那就是,主元法,高斯消元就是這樣的

同時\(i\)行的方程,去將\(i+1\)\(n\)行的方程的某一個元消去

那么最后就會得到一個上三角,對於這個上三角,顯然的,可以從下往上依次解每一個元,時間復雜度即為\(O(n^3)\)

組合數學

容斥

容斥實際上是考慮改變一些限制條件,使得原來不好算的式子變得好算,最典型的莫過於將恰好\(i\)個改變成為至少\(i\)

舉一個例子進行說明傳送門

如果還不懂的話,推薦一個巨佬的博客

排列數和組合數

排列數

定義

\(n\)個物品中不放回地依次選\(m\)個物品,考慮順序,有多少種方案,記作\(A_n^m\)

公式

\(A_n^m=\frac{n!}{(n-m)!}\)

排列數

內容

\(n\)個物品中不放會地依次選\(m\)個物品,不考慮順序,有多少種方案, 記作\(C_n^m\)

公式

\(C_n^m=\frac{A_n^m}{m!}=\frac{n!}{m!(n-m)!}\)

常用的計算方法

根據定義,顯然可以通過預處理階乘來算,

考慮\(C_n^{m-1}\)\(C_n^m\)的關系,顯然有\(C_n^n=C_n^{m-1}*\frac{n-m+1}{m}\)

考慮將\(C\)展開,有

\(\begin{aligned}C_n^m&=\frac{n!}{m!(n-m)!}\\&=\frac{(n-1)!(m+n-m)}{m!(n-m)!}\\&=\frac{(n-1)!m+(n-1)!(n-m)}{m!(n-m)!}\\&=\frac{(n-1)!}{(m-1)!(n-m)!}+\frac{(n-1)!}{m!(n-m-1)!}\\&=C_{n-1}^{m-1}+C_{n-1}^{m}\end{aligned}\)

其實這就是楊輝三角

#### 性質

\(C_n^m=C_n^{n-m}\),根據組合的定義去證明

\(C_{n+m+1}^n=\sum_{i=0}^{m}C_{n+i}^i\)考慮楊輝三角的形式,\(C_n^m\)裂成\(C_{n-1}^{m-1}\)\(C_{n-1}^m\),同時我們又知道\(C_n^0=1\),所以最后一次裂了之后就直接\(C_n^0=C_{n-1}^0\)

\(C_n^mC_m^r=C_n^rC_{n-r}^{m-r}\),根據組合的定義去證明

\(\sum_{i=0}^nC_n^ix^i=(1+x)^n\),二項式定理

\(\sum_{i=0}^nC_n^i=2^n\),當\(x=1\)

\(\sum_{i=0}^nC_n^i(-1)^i=0\),當\(x=-1\)

\(C_n^0+C_n^2+\ldots=C_n^1+C_n^2+\ldots=2^{n-1}\),通過楊輝三角去裂開每一項

\(C_{n+m}^r=\sum_{i=0}^{min(n,m,r)}C_n^iC_m^{r-i}\),根據組合的定義去證明

\(C_{n+m}^n=C_{n+m}^m=\sum_{i=0}^{min(n,m)}C_n^iC_m^i\),通過上一個性質變形可得

\(mC_n^m=nC_{n-1}^{m-1}\),暴力展開即可

\(\sum_{i=0}^{n}iC_n^i=n2^{n-1}\),通過換元有\(\begin{aligned}\sum_{i=0}^{n}iC_n^i+\sum_{i=0}^{n}iC_n^{n-i}&=\sum_{i=0}^{n}iC_n^i+\sum_{i=0}^{n}(n-i)C_n^i\\&=\sum_{i=0}^{n}nC_n^i\\&=n\sum_{i=0}^{n}C_n^i\\&=n2^n\end{aligned}\)

由於\(\sum_{i=0}^niC_n^i=\sum_{i=0}^{n}(n-i)C_n^i\),所以\(\sum_{i=0}^{n}iC_n^i=n2^{n-1}\)

\(\sum_{i=0}^nC_n^ii^2=n(n+1)2^{n-2}\),考慮展開

\(\begin{aligned}\sum_{i=0}^nC_n^ii^2&=\sum_{i=0}^{n}\frac{n!}{i!(n-i)!}i(i-1+1)\\&=\sum_{i=0}^{n}i\frac{n!}{i!(n-i)!}+\sum_{i=0}^{n}i(i-1)\frac{n!}{i!(n-i)!}\\&=\sum_{i=0}^{n}C_n^ii+\sum_{i=1}^{n}i(i-1)\frac{n!}{i!(n-i)!}(當i=0的時候,那一項為0)\\&=n2^{n-1}+\sum_{i=0}^{n-1}(i+1)i\frac{n!}{(i+1)!(n-i-1)!}\\&=n2^{n-1}+\sum_{i=0}^{n-1}i\frac{n!}{i!(n-i-1)!}\\&=n2^{n-1}+n\sum_{i=0}^{n-1}i\frac{(n-1)!}{i!(n-i-1)!}\\&=n2^{n-1}+n\sum_{i=0}^{n-1}iC_{n-1}^i\\&=n2^{n-1}+n(n-1)2^{n-2}\\&=n(2*2^{n-2}+n2^{n-2}-2^{n-2})\\&=n(n+1)2^{n-2}\end{aligned}\)

\(\sum_{i=0}^{n}(C_n^i)^2=C_{2n}^n\),根據\(C_{n+m}^{n}=\sum_{i=0}^{min(n,m)}C_n^iC_m^i\),當\(n=m\)的時候成立

錯排數

定義

\(n\)個編了號的球放進\(n\)個編了號的盒子里面滿足每個盒子有且只有\(1\)個球,同時球的編號和盒子的編號不一樣,滿足這樣的條件的方案總數

遞推式

\(D(n)=(n-1)(D(n-1)+D(n-2)),D(1)=0,D(2)=1\)

假設已經有\(n-1\)個元素實現了錯排,那么新來的元素不管是和誰交換位置都可以實現錯排,此時的方案即為\((n-1)D(n-1)\)

如果已經有\(n-2\)個元素實現了錯排,那么必然有一個元素剛好放在他編號一樣的盒子里面,此時新來的元素必須和這個元素交換位置才能實現整體的錯排,所以方案數即為\((n-1)D(n-2)\)

所以有\(D(n)=(n-1)(D(n-2)+D(n-1))\)

卡特蘭數

定義

給定一個邊長為\(n\)的正方形,考慮從左下角走到右上角,每一次只能往右走或者往上走,且不能越過對角線,即圖中的紅線,方案數記作卡特蘭數\(C(n)\),即在任意時刻向右的步數大於等於向上的步數,

遞推式

\(C(n)=\sum_{i=0}^{n-1}C(i)*C(n-i-1)\),考慮第一次觸碰紅線的時間即可

通項公式

\(C(n)=C_{2n}^n-C_{2n}^{n+1}=\frac{C_{2n}^n}{n+1}\)

如果不考慮紅線的限制,那么方案數為\(C_{2n}^n\),因為操作序列長度為\(2n\),從中選\(n\)個操作是向上,剩下的\(n\)個是向右

接着考慮不合法的方案,如果即跨過了對角線,因為從上面跨到下面和下面跨到上面本質上是一樣的,這里只討論下面跨到上面的情況,我們如果把第一次接觸到綠線以后的操作全部反轉,即向右變成向上,向上變成向右,那么最終一定會到達\((n-1,n+1)\),因為第一次接觸綠線的時候,設向右的步數為\(cnt\),那么向上的步數一定是\(cnt+1\), 剩下的向右的步數即為\(n-cnt\),向上的步數為\(n-cnt-1\),反轉之后向右的步數為\(n-cnt-1\),向上的步數為\(n-cnt\),總過的向右的步數即為\(n-1\) ,向上的步數即為\(n+1\),所以最終一定會達到\((n-1,n+1)\),按照同樣的分析方法可以得到此時的方案數為\(C_{2n}^{n+1}\)

后面那一步推導就是將兩個組合數暴力展開再合並之后的結果

第一類stirling數

定義

考慮把\(n\)個不同的數字分成\(m\)個圓排列的方案數記作\(s_{n,m}\),圓排列指將循環后相等的序列看成同一個序列

遞推式

\(s_{n,m}=s_{n-1,m-1}+(n-1)*s_{n-1,m}\)

邊界條件即為\(s_{n,n}=1\)\(s_{n,1}=(n-1)!\)\(s[n][m]=0[n<m]\)\(s[n][0]=0[n>0]\)

遞推式應該很好理解,就是第\(n\)個數是否是單獨形成一個圓排列

第二類stirling數

定義

考慮把\(n\)個不同的數字分成\(m\)個集合的方案數記作\(S_{n,m}\)

遞推式

\(S_{n,m}=S_{n-1,m-1}+m*S_{n-1,m}\)

與第一類stirling數類似

考慮第\(n\)個數是一個新的集合還是加入原有的集合

邊界條件為\(\begin{cases}S_{n,n}=1\\S_{n,1}=1\\S_{n,m}=0(n<m)\\S_{n,0}=0(n>0)\end{cases}\)

性質

第二類stirling數和冪有一個奇妙的關系

\(n^k=\sum_{i=0}^{k}S(k,i)*C(n,i)*i!\)從組合意義上面去理解,這里的\(i\)為枚舉非空盒子的數量


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM