質數
判斷質數
朴素算法
考慮一個數\(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\)為枚舉非空盒子的數量