数论基础
基础数论
原根
定义:a % m 的阶 = $ \Phi(m)$,a叫m的原根。(我吐了)
定义:\(a^0,a^1,a^2...a^{\phi(m) - 1}\pmod m\),这些数两两不同,则a是\(\pmod m\)意义下的原根。
性质:1.原根一般比较小,大概是小于10或者十几的数吧。
2.一个正整数\(m\),\(m\)有原根当且仅当\(m=2,4,p^a,2*p^a\),\(p\)为奇素数。
那咋求一个数的原根呢?
1.保利写法:
int get_yuan_gen(int p) {
int phip = phi(p);
for(int a = 2; ; a++) {
int x = 1, flag = 1;
for(int i = 0;i < phip; i++) {
z[i] = x;
x = 1ll * x * a % p;
}
sort(z, z + phip);
for(int i = 1;i < phip; i++) {
if(z[i] == z[i - 1]) { flag = 0; break; }
}
if(flag) return a;
}
}
可以看出这个代码复杂度是\(O(k\phi(p))\)的,不太妙。
2.优化写法:
int get_yuan_gen(int p) {
int phip = phi(p);
for(int a = 2; ; a++) {
int flag = 1;
for(int i = 0;i * i <= phip && flag; i++) {
if(phip % i == 0) {
if(ksm(a, i, phip) == 1) flag = 0;
if(ksm(a, phip / i, phip) == 1) flag = 0;
}
}
if(flag) return a;
}
}
时间复杂度是\(O(k\sqrt{\phi(p)} )\),挺妙的。
为啥这么写,证明:
当前枚举到的数\(g\)如果不是原根,那么必定有:\(g^a \equiv g^b \pmod{p}\)。
化简一下得:\(g^{a - b} \equiv 1 \pmod{p}\)。
根据欧拉定理我们知道:\(g^{\phi(p)} \equiv 1 \pmod{p}\)。
所以:\(a - b | \phi(p)\)。我们只需找一个\(\phi(p)\)的约数\(k\),然后判断是否\(g^k \equiv 1 \pmod {p}\)就可以了。
Miller_Rabin素性测试
如何快速判断一个\(10^{18}\)大小的数是否是素数,如果采用\(O(\sqrt n)\)可能很悬,这时候就要用到Miller_Rabin来判断素数了。
令\(n = 2 ^r +d - 1\),取\(0\le a < n\),若\(n\)为素数,则一定满足以下两个条件其中之一:
1.\(a^d \equiv 1 \pmod{n}\)。
2.存在\(0 \le i < r\),使\(a ^ {d * 2 ^ i} \equiv n - 1\pmod{n}\)。
证明:费马小定理。
如果一个数满足这两个条件,那么它可能是素数。我们现在多枚举几个\(a\),让\(n\)多经过几次测试,每次通过测试的概率可以认为是\(\frac{1}{2}\)(事实上比\(\frac{1}{2}\)还要大),十次测试过后,这个数是素数的概率变为了\(\frac{1023}{1024}\),接近于一,可以说非常大了。(一个大佬说好像long long范围内的数都不会被卡)
bool miller_rabin(int n, int a) {
int d = n - 1, r = 0;
while(d % 2 == 0) d /= 2, r++;
int x = ksm(a, d, n);
if(x == 1) return 1;
for(int i = 0;i < r; i++) {
if(x == n - 1) return 1;
x = 1ll * x * x % n; //a^d, a^2d, a^4d, a^8d...
}
return 0;
}
int prime[10] = {0, 2, 3, 5, 7, 11, 23, 37, 47};
bool is_prime(int n) {
for(int i = 1;i <= 8; i++) {
if(!miller_rabin(n, prime[i])) return 0;
}
return 1;
}
复杂度\(O(klogn)\)。很妙。
狄利克雷卷积
定义:\((f*g)(n) = \displaystyle \sum_{d|n} f(d) * g(\frac{n}{d})\)
性质:1.交换律:\(f*g = g * f\);
2.结合律:\((f*g)*h = f * (g * h)\);
3.分配率:\((f + g) * h = f * h + g * h\)。
(有了这些性质可以把它理解为函数的乘法操作)
重要等式:1.\(\mu * I = \epsilon\) $ (\epsilon(n) = [n = 1], I(n) = 1)$
2.\(\phi * I = id\) \(id(n) = n\)
3.\(\mu * id = \phi\)
重要等式证明:
1.\(\mu * I = \epsilon\)
2.\(\phi *I = id\) 这个其实举例子就可以了,严谨的证明我不太会
数学上有一个方法叫数学归纳法,把\(n\)的逐渐一般化,过程太复杂了(我吐了)。
3.\(\mu * id = \phi\) 这个把等式1,2带进去就好了
莫比乌斯反演
如果\(g(n) = \displaystyle \sum_{d|n} f(d)\),则\(f(n) = \displaystyle \sum_{d|n} \mu(d) * g(\frac{n}{d})\)。
那样不好看,这样才好看:\(g = f * I \Leftrightarrow f = \mu * g\)。这个过程就叫反演。
\(\mu * g = \mu * f * I = \mu * I * f = \epsilon * f = f\)。(\(\epsilon\)卷上任何函数都是它本身)
变换手段:1.增加枚举量。 2.交换枚举顺序。