刘汝佳-训练指南-数论-基本概念

  1. 素数 因子只有1和本身;
#define maxn 100000

int vis[maxn], prime[maxn];//vis为1-合数,vis为0-素数1
int n;
void seize(int n) {			//筛掉素数
	int m = sqrt(n) + 0.5;
	memset(vis, 0, sizeof(vis));
	for (int i = 2; i <= m; i++)  //因子最大不超过sqrt(n),以其为界
		if (!vis[i]) {    
		for (int j = i * i; j <= n; j+=i)   //最小质因子的倍数一定是合数;
			vis[j] = 1;
	}
}

void get_prime(int n)    //打表
{
	seize(n);
	int c = 0;
	for (int i = 2; i < n; i++) {    
		if (!vis[i])   prime[c++] = i;
	}
}
  1. 欧几里得算法,一种求最大公约数的强大算法,
int  gcd(int a, int b) {
	return b == 0 ? a : gcd(b, a%b);
}

拓展欧几里得算法-不仅可以求出两个数a与b之间的余数,还可以求出关于
ax+by=gcd(a,b)的x,y的解:
两种方法


int  exgcd(int a, int b, int &x, int &y) {
	if (!b) {
		x = 1, y = 0;
		return  a;
	}
	int r=exgcd(a, b, x, y);
	int temp = x;
	y = x - a/b*y;
	x = temp;
	return r;	
}

蓝书的算法

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

问:拓展欧几里得算法为什么可以求出形如ax+by=gcd(a,b)的x,y的特解?(第一种方法)
答: 我们姑且将gcd(a,b)用g(a,b)表示,对于a和b而言,g(a,b)是它们的最大公约数.我们想一下拓展欧几里得递归的最后一层 a=g(a,b),b=0;
此时对于这一层的二元一次方程式带入后应该是,(g(a,b)x)+(by)=g(a,b)化简得 x=1,y=0;那么本层得x,y与上面一层之间有什么联系呢。换言之,我们现在讨论倒数第二层,本层x,y与倒数第一层x,y有什么联系呢。
我们先列出方程
本层 :ax0+by0=g(a,b);
下一层: bx1+(a%b)y1=g(a,b)
我们将两个方程联立 得出 ax0+by0=bx1+(a%b)y1
由于 a%b=a-(a/b)*b,我们将其替换,得;
ax0+by0=bx1+(a-(a/b)*b)y1
ax0+by0=bx1+ay1-(a/b)*by1,继续化简,得;
ax0+by0=ay1+b(x1-(a/b)y1),可得;
x0=y1,y0=x1-(a/b)y1,这样每一层的x,y 值都可以由上一层的x,y值得出来,于是乎,递推至最高,便可得出最高层的x,y值,注意,这只是一组特解;
通解可以用 y=y0-at,x=x0+at;(t为任意整数,),算我多说一句,这两个式子是如何得来的呢; ax+by=a(x0+at)+b(y0-at)=g(a,b);因此x=x0+at,y=y0-at(谁加,谁减都无所谓,因为t有正有负)记住,我们求解的是整数.

3.模运算
基本的加减:
(a + b)%c = (a%c + b%c)%c
(a − b)%c = (a%c − b%c + c)%c

  • 乘积取模:
    (ab)%c = (a%c)(b%c)%c
    幂取模
    a^bmod c=(a%c)*(a%c)^^^^
	ll mul_mod(ll a, ll b, int n) {
	return a * b%n;
}

ll pow_mod(ll a, ll p, ll n) {
	if (!p)  return 1;
	ll ans = pow_mod(a, p / 2, n);
	ans = ans * ans*a%n;
	if (!(p & 1)) ans = ans * ans%n;
	return ans;
}

4.欧拉函数。欧拉函数phi(x)等于不超过x且和x互素的整数个数。
p h i ( m ) = ∏ i = 1 n ( 1 − 1 / p i ) phi(m)=\prod^{n}_{i=1}(1-1/p_i) phi(m)=i=1n11/pi
其中pi表示整数n的因子,每个因子只参与一次。
下面给出求单个值得不超过n且与n互素得正整数的个数

int euler_phi(int n) {
	int m = (int)sqrt(n + 0.5);
	int ans = n;
	for (int i = 2; i <= m; i++)  if (n%i == 0) {
		ans = ans / i * (i - 1);
		while (n%i == 0)  n /= i;   //将已经记录的因子除干净
	}
	if (n > 1)  ans = ans / n * (n - 1);
}
	

打表的


int phi[10000];
void phi_table(int n) {
	for (int i = 2; i <= n; i++)  phi[i] = 0;
	phi[1] = 1; 
	for (int i = 2; i <= n; i++)  if (!phi[i]) {  //从因子开始枚举
		for (int j = i; j <= n; j += i) {
			if (!phi[j])  phi[j] = j;
			phi[j] = phi[j] * (i - 1) / i;
		}
	}
 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值