數論總結——更新ing

DreamW1ngs發表於2020-11-15

數論還是有很多沒學完 只是小小的總結

一、同餘定理

1.反身性:\(a\equiv a (mod m)\)
2.對稱性:若\(a\equiv b(mod m)\),則\(b\equiv a (mod m)\)
3.傳遞性:若\(a\equiv b(mod m)\)\(b\equiv c(mod m)\),則\(a\equiv c(mod m)\)
4.同餘式相加:若\(a\equiv b(mod m)\)\(c\equiv d(mod m)\),則\(ac\equiv bd(mod m)\)
5.同餘式相乘:若\(a\equiv b(mod m)\)\(c\equiv d(mod m)\),則\(ac\equiv bd(mod m)\)

二、最小公倍數與最大公約數

最大公約數:GCD
輾轉相除法:設\(gcd(a,b)\)\(a\)\(b\)的最大公約數

\[gcd(a,b)=gcd(a-b,b)\Rightarrow gcd(a,b)=gcd(b,a\%b) \]

\(b\)為0時,此時的\(a\)即為二者的最大公約數

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

最小公倍數:LCM
\(d=gcd(a,b)\)\(a=a'd\)\(b=b'd\),可以看出 \(lcm(a,b)=\frac{ab}{gcd(a,b)}\)

三、整除

給定\(a\),\(b\)兩個數,若b能整除a,記作\(b\mid a\),反之記作\(a\nmid b\)
簡單定理:

  • \(b\mid a\),且\(c\mid b\),則\(c\mid a\)
  • \(c\mid a\),且\(c\mid b\),則\(c\mid \left(na+mb\right)\)

四、素數與合數

對於任意一個大於1的自然數,只有1和它本身兩個因子,則稱為素數
素數定理:小於等於x的素數個數 \(\approx \frac{x}{\ln x}\) ,可以用來估計素數個數,進而估算所開陣列的大小
不是素數的大於1的自然數稱為合數

素數篩法:

1、暴力列舉

複雜度:\(O(\log{n})\)
由於任意一個數\(x\)的因子可看為兩部分,小於\(\sqrt{x}\)與大於\(\sqrt{x}\),因此可以列舉所有\(\{i\mid i\le \sqrt{x}\}\),如若出現\(i\mid x\),則不是素數,反之是素數。
一般用於對某單個數的素性判定

bool check(int x)
{
	int end = sqrt(x);
	for (int i = 2; i <= end; ++i)
	{
		if (x % i == 0)
			return false;
	}
	return true;
}

擴充內容(求單個合數的最大質因數)
對於任何一個數\(x\),可以將他進行質因數分解,且同時保證\(prime[i]^2\le x_{cur}\)進行優化。
首先可以預處理出所有\(\{prime\mid prime \le \sqrt{x}\}\),這樣\(x\)的質因數分解一定是在這個集合中,或者只有最大質因數不在這個集合中。如果所剩下的最後一個數為1,即完美的進行了質因數分解,則最大質因數為最後一次除的質數,反之則最後剩下的數即為最大質因數

const int maxn = 10000;
int vis[maxn];
int cnt, prime[maxn/10];

void Euler_Sieve()
{
	for (int i = 2; i < maxn; ++i)
	{
		if (!vis[i]) prime[cnt++] = i;
		for (int j = 0; j < cnt && prime[j] * i < maxn; ++j)
		{
			vis[prime[j] * i] = true;
			if (i % prime[j] == 0)
				break;
		}
	}
}
int Maximum_prime_factor(int x)
{
	int ans;
	for (int i = 0; i < cnt && prime[i] * prime[i] <= x; ++i)
	{
		if (x % prime[i] == 0)
		{
			ans = prime[i];
			while (x % prime[i] == 0)
				x /= prime[i];
		}
	}
	return x == 1 ? ans : x;
}

2、埃氏篩法

複雜度:\(O(\log{\log{n}})\)
由於對於任何合數而言,他們能夠被任意\(prime\) 整除,所以,可以通過列舉\(k*prime(k*prime\le lim_{up})\),來篩選出一些約數,而沒有被篩選過的自然就是素數
值得說明的是:當選中某個\(prime\)時,比\(prime\)小的質數的倍數已經被篩出了,所以為了減小時間複雜度,可以從\(prime^2\)開始篩選

const int maxn = 10000;
bool vis[maxn];
int cnt, prime[maxn / 10];
void Eratosthenes_Sieve()
{
	for (int i = 2; i < maxn; ++i)
	{
		if (vis[i]) continue;
		prime[cnt++] = i;
		for (int j = i * i; j < maxn; j += i)
			vis[j] = true;
	}
}

擴充內容(求出多個合數的最大質因數)
利用埃氏篩法是由小質數到大質數的篩選過程,每次大質數篩選時會覆蓋之前小質數的結果,因此可以得到實現程式碼
注意:開始條件從\(i^2\)變為了\(2i\)

#include<cstdio>
const int maxn = 10000;
int vis[maxn];
int cnt, prime[maxn / 10];
void get_Maximum_prime_factors()
{
	for (int i = 2; i < maxn; ++i)
	{
		if (vis[i]) continue;
		prime[cnt++] = i;
		for (int j = 2*i; j < maxn; j += i)
			vis[j] = i;
	}
}

3、尤拉篩

複雜度:\(O(n)\)
通過對每個合數,只用其最小的質因數進行篩選的思想,每次將\(cur*prime[i]\)對應的數篩出,為了保證最小的質因數篩出,當\(prime[i]\mid cur\)時,需要break
原因在於設\(cur=k*prime[i]\),那麼如果繼續篩即對於

\[n=cur*prime[i+1]=(prime[i]*k)*prime[i+1]=prime[i]*(k*prime[i+1]) \]

則可以看出來,這個數\(n\)本應該在列舉到數\(k*prime[i+1]\)(比\(cur\)大)被\(prime[i]\)篩出

void Euler_Sieve()
{
	for (int i = 2; i < maxn; ++i)
	{
		if (!vis[i]) prime[cnt++] = i;
		for (int j = 0; j < cnt && prime[j] * i < maxn; ++j)
		{
			vis[prime[j] * i] = true;
			if (i % prime[j] == 0)
				break;
		}
	}
}

擴充內容(求出多個合數的最小質因數)
利用尤拉篩每個數都被其最小質因數所篩去
注意:開始條件從\(i^2\)變為了\(2i\)

#include<cstdio>
const int maxn = 10000;
int vis[maxn];
int cnt, prime[maxn / 10];
void get_Maximum_prime_factors()
{
	for (int i = 2; i < maxn; ++i)
	{
		if (!vis[i]) vis[i] = prime[cnt++] = i;
		for (int j = 0; j < cnt && prime[j] * i < maxn; ++j)
		{
			vis[prime[j] * i] = prime[j];
			if (i % prime[j] == 0)
				break;
		}
	}
}

4、杜教篩

待學

5、min25篩

待學

五、尤拉函式

相關文章