數論

zhengchenxi發表於2024-07-22

求逆元

費馬小定理
擴充套件歐幾里得
線性求逆元

中國剩餘定理

形如

\[x \equiv a_1 \pmod {n_1} \]

\[x \equiv a_2 \pmod {n_2} \]

\[x \equiv a_3 \pmod {n_3} \]

\[x \equiv a_4 \pmod {n_4} \]

image
OI-WIKI

點選檢視程式碼
LL CRT(int k, LL a[], LL r[]) {
  LL n = 1, ans = 0;
  for (int i = 1; i <= k; i++) n = n * r[i];
  for (int i = 1; i <= k; i++) {
    LL m = n / r[i], b, y;
    exgcd(m, r[i], b, y);  // b * m mod r[i] = 1
    ans = (ans + a[i] * m * b % n) % n;
  }
  return (ans % n + n) % n;
}

擴充套件中國剩餘定理

在某些條件下模數\(n_i\)不一定為質數,這就需要用到擴充套件中國剩餘定理
假設已經求出前k-1個方程組成的同餘方程組的一個解為x
且有\(M=\prod_{1到i-1}^{1到k-1}m_i\)這相當於前i-1個m的最大公倍數即為\(M=LCM_{1到i-1}^{1到k-1}m_i\)還更能防止溢位
則k-1個方程的通解為\(x+i*M(i\in Z)\)
則對於第k個方程為\(x+t*M\equiv a_k (mod m)\)
移一下項\(t*M\equiv a_k-x (mod m)\)
然後我們可用擴充套件歐幾里得t
不過根據裴蜀定理
這樣的方程存在解的必要條件為\(gcd(a,b)∣c\)
所以無解就輸出-1
所以整個演算法的思路就是求解k次擴充套件歐幾里得
M∗=bg明顯就是令M為前k個m的最小公倍數

  • ii即為__int128不想用的話可以用龜速乘
點選檢視程式碼
ii exCRT()
{
	ii x,y,k;
	ii M=m[1],ans=a[1];//mod num
	for(int i=2;i<=n;i++)
	{
		ii A=M,b=m[i],c=((a[i]-ans)%b+b)%b;
		ii gcd=exgcd(A,b,x,y),bg=b/gcd;
		if(c%gcd!=0)return -1;
		x=x*c/gcd%bg;
		ans+=x*M;//更新前k個方程組的答案
		M*=bg;//M為前k個m的lcm
		ans=(ans%M+M)%M;
	}
	return (ans%M+M)%M;
}

Lucas定理

求解組合數取模問題,其中模數必須為素數
C(n,m)modp

  1. 當n很大且n<p可用乘法逆元
  2. 當n>p公式上的分母可能沒有逆元,此時需要Lucas
初始化
void getp()
{
	phi[1]=phi[0]=1;
	for(int i=2;i<mod;i++)
	{
		phi[i]=(mod-mod/i)*phi[mod%i]%mod;
	}
	b[1]=b[0]=1;
	for(int i=2;i<mod;i++)
	{
		b[i]=b[i-1]*phi[i]%mod;
	}
	jie[1]=jie[0]=1;
	for(int i=2;i<mod;i++)
	{
		jie[i]=jie[i-1]*i%mod;
//		cout<<jie[i]<<endl;
	}
}
點選檢視程式碼
int C(int n,int m)
{
	return n<m?0:jie[n]*b[n-m]*b[m]%mod;
}
int lucas(int n,int m)
{
	if(m==0)return 1;
	if(m>n-m)
	{
		m=n-m;
	}
	return lucas(n/mod,m/mod)*C(n%mod,m%mod)%mod;
}

求解

對於素數p

\[C_{n}^m=C_{[n/p]}^{[m/p]}*C_{[n mod p]}^{[m mod p]} \]

p的範圍不能夠太大,一般在\(10^5\)左右
邊界條件:當m=0的時候,返回 1
注意 n%p<m%p時,組合數為0
image

二項式

\[(a+b)^p=\sum_{m=0}^pC_p^ma^mb^{p-m} \]

對兩邊取模
\((a+b)^p \equiv a^p+b^p (mod p)\)

擴充套件盧卡斯定理(exLucas)

\(p\)不是質數時,需要用到擴充套件盧卡斯定理求解。
由於模數\(p\)不是質數,由唯一分解定理

\[p=\prod_{i=1}^{r}p_i^{a_i} \]