0120数论小结

PART 1 素数筛

埃氏筛

逆用试除法 —— 用素数排除合数

没什么好说的

//埃氏筛
void Eratosthenes() {
	vis[0] = vis[1] = false; //提前处理好1与0 合数标记为false,素数标记为true
	for (int i = 2; i <= sqrt(n); i++) { 
		if (vis[i] == true) { // i 为 素数
			for (int j = i * i; j <= n; j += i) { //标记i^2 ~ n 中所有素数i的倍数
				vis[j] = false;
			}
		}
	}
} 

例题:找质数2【竞速赛Round3】How many primes?

应用场景较广,适用大部分题。

时间复杂度:O(nlogn)

Tips: 注意题目N的范围, 若多组样例,思考是否预处理。

欧拉筛(线性筛)

每次筛掉部分素数倍数,而非一次性筛完所有倍数

有说的但我不是很会

void ols() {
	int cnt = 0;
	for (int i = 2; i <= n; i++) {
		if (vis[i] == true) prime[++cnt] = i;
		for (int j = 1; j <= cnt && i * prime[j] <= n; j++) { // 避免超出范围
			prime[i * prime[j]] = false; //只筛除一部分
			if (i % prime[j] == 0) break;
		}
	}
}

速度较快,适用几乎所有题

时间复杂度:O(n)

PART 2 同余方程

//同余方程
int exgcd (int a, int b, int &x, int &y) {
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	} else {
		int d = exgcd (b, a % b, y, x); //辗转相除
		y -= a / b * x;
		return d;
	}
}

题目通常为数学问题,会直接点出“同余”

例题:【NOIP2012 day2】同余方程青蛙的约会

PART 3 欧拉函数

通式:fai(x) = x * ( 1 - 1 / p1) * (1 - 1 / p2)……* (1 - 1 / pn)

p1,p2,p3……pn为x的所有质因数

法1:基于素因数分解求欧拉函数

int euler (int x) { //基于整数分解定理
	int ans = x;
	int a = x;
	for (int i = 2; i <= sqrt(a); i++) {
		if (a % i == 0) ans -= ans / i;
		while (a % i == 0) a /= i; //除尽质因子i
	}
	if (a > 1) ans -= ans / a; //防止a为质数
	return ans;
}

• 时间复杂度为O(sqrt(n))

Tips:只能求出一个数

法2:埃氏筛(打表)

void euler(int n) {
	for (int i = 1; i <= n; i++) phi[i] = i;
	for (int i = 2; i <= n; i++) {
		if (phi[i] == i) {
			for (int j = i; j <= n; j += i) {
				phi[j] = phi[j] / i * (i - 1);
			}
		}
	}
}

可以求出1~n中所有的fai(i)

补充:快慢乘

//快慢乘
int quick (int a, int b, int mod) {
	int ans = 0;
	while (b) {
		if (b & 1) ans = (ans + a) % mod;
		a = (a << 1) % mod;
		b >>= 1;
	}
	return ans;
}
int slow (int a, int b, int mod) {
	int ans = 0;
	while (b > 0) {
		if (b & 1) ans = (ans + a) % mod;
		b >>= 1;
		a = (a + a) % mod;
	}
	return ans;
}
int mod (int a, int b, int mod) {
	int sum = 1;
	while (b > 0) {
		if (b & 1) sum = slow(sum, a, mod);
		a = slow(a, a, mod);
		b >>= 1;
	}
	return sum;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值