数论入门基础整理

*有误欢迎大佬斧正*

基本定理:

威尔逊定理:一个数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, M= 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 + r)...( 1 + r)

x的所有因子之和:( 1 + p+ p12 + p13...p1r1)( 1 + p+ p22  +...+p2r2)...( 1 + p+ pn+ ...+ 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 }
求n!里因子p的个数

 

 素数筛

埃氏筛素数(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 }
Miller-Rabin大素数测试

 

 

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的幂次需要特判

 

 

 

 

posted @ 2019-08-04 16:11  mool  阅读(1506)  评论(0编辑  收藏  举报