数论入门基础整理
*有误欢迎大佬斧正*
基本定理:
威尔逊定理:一个数p为素数的充要条件是p|(p-1)!+1
费马小定理:对于素数p,以及整数a,如有(a,p)=1,则a^(p-1)=1(mod p)
欧拉定理:对于任意两个互素整数a,m ,a^φ(m) =1 (mod m), φ为欧拉函数,表示小于p且与p互素的数个数
欧拉函数求解:
1 int euler(int x) 2 { 3 int res = x, n = x; 4 for (int i = 2; i * i <= n; i++) 5 if (n % i == 0) 6 { 7 res = res / i * (i - 1); 8 while (n % i == 0) 9 n /= i; 10 } 11 if (n > 1) 12 res = res / n * (n - 1); 13 return res; 14 }
1 void getEuler() 2 { 3 for (int i = 1; i < maxn; i++) 4 e[i] = i; 5 for (int i = 2; i < maxn; i++) 6 if (e[i] == i) 7 for (int j = i; j < maxn; j += i) 8 e[j] = e[j] / i * (i - 1); 9 }
扩展欧拉定理:将欧拉定理延申到了 (a,m) !=1 的情况,可用于大指数运算
<code>
孙子定理(中国剩余定理):
对于形如的方程组,m互素
令M=m1*m2..mn, Mi = M/mi, ti=Mi在模mi意义下的乘法逆元(关于乘法逆元可以参考费马小定理或扩展欧几里得算法),解为
x=a1*t1*M1+a2*t2*M2+...an*tn*Mn+kM,k为整数,原方程最小解为x mod M
1 /* 2 普通孙子定理/中国剩余定理,求解模数互素的同余方程组 3 m除数,r余数 4 */ 5 ll exgcd(ll a, ll b, ll &x, ll &y) //求逆元 6 { 7 if (b == 0) 8 { 9 x = 1, y = 0; 10 return a; 11 } 12 ll ret = exgcd(b, a % b, y, x); 13 y -= (a / b) * x; 14 return ret; 15 } 16 17 ll crt() 18 { 19 ll d, x, y, ret = 0; 20 ll temp; 21 ll M = 1; 22 for (int i = 0; i < n; i++) 23 M *= m[i]; //m是除数 24 for (int i = 0; i < n; i++) 25 { 26 temp = M / m[i]; 27 d = exgcd(m[i], temp, x, y); //求temp在模mi意义下的逆元 28 ret = (ret + y * temp * r[i]) % M; //b是余数 29 } 30 return (ret + M) % M; 31 }
对于m不互素的情况,需要用扩展欧几里得进行两两合并求解()
1 /* 2 扩展中国剩余定理 3 可求解m不互质的同余方程组 4 m除数,r余数 5 */ 6 7 ll exgcd(ll a, ll b, ll &x, ll &y) 8 { 9 if (b == 0) 10 { 11 x = 1, y = 0; 12 return a; 13 } 14 ll ret = exgcd(b, a % b, y, x); 15 y -= (a / b) * x; 16 return ret; 17 } 18 ll excrt() 19 { 20 ll M = m[0], R = r[0], x, y, d; 21 for (int i = 1; i < n; i++) 22 { 23 d = exgcd(M, m[i], x, y); 24 if ((R - r[i]) % d) 25 return -1; 26 x = (R - r[i]) / d * x % m[i]; 27 R -= M * x; 28 M = M / d * m[i]; 29 R %= M; 30 } 31 return (R % M + M) % M; 32 }
素数与合数:
唯一分解定理
一个自然数x可以唯一分解为x = p1r1p2r2...pnrn (p为素数,r为正整数)
x的所有因子个数:(1 + r1) * ( 1 + r2 )...( 1 + rn )
x的所有因子之和:( 1 + p1 + p12 + p13...p1r1)( 1 + p2 + p22 +...+p2r2)...( 1 + pn + pn2 + ...+ pnrn)
x的所有素因子之和: phi(n)*n/2, (phi为欧拉函数,表示小于n且与n互素的数个数)
反素数
定义g(x)为x的因子个数,若对于所有的0 < i< x,都有g(i)<g(x)则称x为反素数
反素数性质1:一个反素数的素因子必然是从2开始的连续素数
反素数性质2:若n为反素数,则n= p1r1p2r2...pnrn ,其中r1>=r2>=..rn
N!的素因子分解:
即幂可由后边和式计算得到
1 int f(ll n, ll p) 2 { 3 if (n == 0) 4 return 0; 5 return f(n / p, p) + n / p; 6 }
素数筛
埃氏筛素数(no code)
1 for (int i = 2; i <= maxn; i++) 2 { 3 if (!vis[i]) 4 prime[pcnt++] = i; 5 for (int j = 0; j < pcnt && i * prime[j] <= maxn; j++) 6 { 7 vis[i * prime[j]] = 1; 8 if (i % prime[j] == 0) 9 break; 10 } 11 }
1 /* 2 区间素数筛,maxn是区间长度,[a,b] 3 */ 4 const int maxn = 1e5 + 10; //区间最大长度 5 bool isprime1[maxn], isprime2[maxn]; 6 int solve(ll a, ll b) 7 { 8 for (ll i = 0; i * i <= b; i++) 9 isprime1[i] = 0; 10 for (ll i = 0; i <= b - a; i++) 11 isprime2[i] = 1; 12 for (ll i = 2; i * i <= b; i++) 13 { 14 if (!isprime1[i]) 15 { 16 for (ll j = i + i; j * j <= b; j += i) 17 isprime1[j] = 1; 18 for (ll j = max(2LL, (a + i - 1) / i) * i; j <= b; j += i) 19 isprime2[j - a] = 0; 20 } 21 } 22 int sum = 0; 23 for (int i = 0; i <= b - a; i++) 24 if (isprime2[i]) 25 sum++; 26 if (a == 1) 27 --sum; 28 return sum; 29 }
MIller-Robin素数测试法
费马小定理:对于素数p和任意整数a,若(a,p)=1,有ap-1 ≡ 1 (mod p)。相反的,满足ap-1 ≡ 1 (mod p),p也几乎一定是素数。
伪素数:如果n是一个正整数,如果存在和n互素的正整数a满足 an-1 ≡ 1(mod n),我们说n是基于a的伪素数。如果一个数是伪素数,那么它几乎肯定是素数。
Miller-Rabin测试:不断选取不超过n-1的基b(s次),计算是否每次都有bn-1 ≡ 1(mod n),若每次都成立则n是素数,否则为合数。
1 ll powerMod(ll a, ll b, ll mod) 2 { 3 ll ret = 1LL; 4 a %= mod; 5 while (b) 6 { 7 if (b & 1LL) 8 ret = multiMod(ret, a, mod), --b; 9 b >>= 1LL; 10 a = multiMod(a, a, mod); 11 } 12 return ret; 13 } 14 15 //Miller-Rabin测试,测试n是否为素数 16 bool Miller_Rabin(ll n, int repeat) 17 { 18 if (2LL == n || 3LL == n) 19 return true; 20 if (!(n & 1LL)) 21 return false; 22 23 //将n分解为2^s*d 24 ll d = n - 1LL; 25 int s = 0; 26 while (!(d & 1LL)) 27 ++s, d >>= 1LL; 28 29 srand((unsigned)time(0)); 30 for (int i = 0; i < repeat; ++i) 31 { //重复repeat次 32 ll a = rand() % (n - 3) + 2; //取一个随机数,[2,n-1) 33 ll x = powerMod(a, d, n); 34 ll y = 0LL; 35 for (int j = 0; j < s; ++j) 36 { 37 y = multiMod(x, x, n); 38 if (1LL == y && 1LL != x && n - 1LL != x) 39 return false; 40 x = y; 41 } 42 if (1LL != y) 43 return false; 44 } 45 return true; 46 }
Pollard-rho大数分解
--摘自大佬博客https://blog.csdn.net/Sunshine_cfbsl/article/details/52512706
对于一个大整数n,我们取任意一个数x使得x是n的质因数的几率很小,但如果取两个数x1以及x2使得它们的差是n的因数的几率就提高了,如果取x1以及x2使得gcd(abs(x1−x2),n)>1的概率就更高了。这就是Pollard-Rho算法的主要思想。
对于满足gcd(abs(x1−x2),n)>1的x1和x2,gcd(abs(x1−x2),n)就是n的一个因数,只需要判断它是否为素数,若为素数,则是n的质因数,否则递归此过程。
其中判断素数就使用MillerMiller-RabinRabin算法。
那么我们怎样不断取得x1x1和x2x2呢?
x1在区间[1,n]中随机出来,而x2则由x[i]=(x[i-1]*x[i-1]%n+c)%n推算出来,其中c为任意给定值,事实证明,这样就是比较优的。
<code>
莫比乌斯反演
专门开了一篇随笔记录,传送门
原根
(埋坑)
勾股数组
本源勾股数组
指勾股数中两两互质的勾股数,其他勾股数均可由其翻倍得出。
求法
对于一个大于1的奇数p,由其构成的本源勾股数组为$p,\left\lfloor\frac{p^2}{2}\right\rfloor,\left\lceil\frac{p^2}{2}\right\rceil$
一般勾股数组的求法,寻找一个奇因子,由奇因子生成本源勾股数组,乘上倍数。特别的,2的幂次需要特判