Part 1【同余相关、phi&u】
答案是会什么,什么都不会。
1.Exgcd
裴蜀定理:\(ax+by=c\) 有解当且仅当 \(c=k \times (a,b)\)。整数条件下。
推广:
对于任意 \(x_1,x_2,...,x_m\)。当 \((a_1,a_2,...,a_m) | c\) 有解。应用见 CF19xxD。
现在我们要得到 \(ax+by=c\) 的一个解。不妨先解 \(c=(a,b)\),再乘一个系数。
考虑 gcd 的辗转相除法:\((a,b)=(b,a\bmod b)\)。
所以我们有:\(ax+by=(a,b),bx'+(a\bmod b)y'=(b,a\bmod b)\)。
注意,这里 \(x',y'\) 是根据 \((b,a\bmod b)\) 得到的,我们需要还原使得 \(x,y\) 对应 \((a,b)\)。
所以 \(ax+by=bx'+(a\bmod b)y'=ay'+b(x'-\lfloor \frac{a} {b}\rfloor y')\)。
那么递归求解,取 \(x=y',y=x'-\lfloor \frac{a} {b}\rfloor y'\) 即可。
边界?普通 gcd 可知 \(b_0=0,a_0=(a,b)\),此时取 \(x_0=1,y_0=0\) 即满足。(此时 \(b\) 直接是 \(0\) 了,所以变成了 1 元方程)
void exgcd(int a, int b, int &x, int &y) {
if(!b) return x = 1, y = 0, void();
exgcd(b, a % b, y, x), y -= a / b * x;
}
1.1 通解
直接给出结论:设 \(d=(a,b)\)。
\(x=x_0+\frac{b}{d}k,\) \(y=y_0-\frac{a}{d}k\)。
可以根据这个求范围内的最大最小值,解的个数等信息……
并且该算法有一个性质就是你求得的 \(x,y\) 满足在所有解中 \(|x|+|y|\) 最小。
1.2 应用
- 转化方程 \(ax\equiv b \pmod p\) 为二元一次方程求解,比如求逆元。也可以根据这个知道使用条件是 \(a\bot p\)。
1.3 例题
先鸽。
2. BSGS
求解方程
2.1 特殊情况
一个很重要的前提:\(x\) 一定在 \([0,p)\) 有解。
设 \(x=AM-B(B \in [0,M))\),类似除和模。变形:\(a^{AM}\equiv ba^B\pmod p\)。
取 \(M=\sqrt p\)。那么右边就只有根号种取值,左边也只有根号种取值。
那就简单了,预处理出左边,枚举右边即可,由于可能要用 map,所以复杂度根号对数。
2.2 ExBSGS
注意上面的算法有一个前提:\(a\bot p\)。
why?因为你把 \(a^B\) 移过去需要这个前提,否则显然不成立。
那干脆就强制改成互质。每次对一个 \(a\) 和 \(p\) 除以 gcd \(D\):
你把 \(a/D\) 移过去,因为和 \(p/D\) 互质所以可以用 exgcd 求逆元。
注意到 \(a\) 和 \(p/\gcd(a,p)\) 不一定互质,所以要一直循环下去做,直到 \(a\bot p\)。
注意取模,特判 \(b=1\) 返回 \(0\)。
时间复杂度 \(O(\sqrt p+\log^2 p)\)。代码中 BSGS 返回了最小的 \(x\)。
int qkpow(int a, int b, int Mod) {
if(!b) return 1;
if(b & 1) return a * qkpow(a, b - 1, Mod) % Mod;
int t = qkpow(a, b >> 1, Mod); return t * t % Mod;
}
void exgcd(int a, int b, int &x, int &y) {
if(!b) return x = 1, y = 0, void();
exgcd(b, a % b, y, x), y -= a / b * x;
}
int inv(int x, int p) { int sb; exgcd(x, p, sb, *new int); return (sb % p + p) % p; }
map <int, int> mp;
int BSGS(int a, int b, int p) {
int A = 1, B = sqrt(p) + 1; mp.clear();
for(int i = 1; i <= B; i++) mp[(A = A * a % p) * b % p] = i;
for(int i = 1, AA = A; i <= B; i++, AA = AA * A % p)
if(mp[AA]) return i * B - mp[AA];
return -1;
}
void ExBSGS(int a, int b, int p) { // 最终要使得 a, p 互质
int s = 0; a %= p, b %= p;
while(__gcd(a, p) != 1) {
if(b == 1) return printf("%lld\n", s), void();
int D = __gcd(a, p);
if(b % D) return puts("No Solution"), void();
b /= D, p /= D; b = b * inv(a / D, p) % p;
++s; a %= p;
}
int ans = BSGS(a, b, p);
if(ans == -1) puts("No Solution");
else printf("%lld\n", ans + s);
}
3. CRT
中国剩余定理。中国真是太厉害啦。
3.1 互质情况
即,\(\forall i\neq j,m_i\bot m_j\)。
勾石。
设 \(X=\sum a\times c\),考虑方程 \(i\),\(X=\sum\limits_{j\neq i}a_jc_j + a_ic_i\),要求前面一坨无关,即是 \(m_i\) 的倍数。而 \(c_i\) 却不能是 \(m_i\) 的倍数。
给出构造:\(c_i=\dfrac{M}{m_i}\),其中 \(M=\prod m_i\)。
发现不够,还需要一个 \(d_i\),因为每个方程要有:\(a_ic_id_i\equiv a_i \pmod {m_i}\),那么自然就有 \(d_i\) 为 \(c_i\) 模 \(m_i\) 的逆元。因为 \(m_i\) 不一定质数,而 \(c_i\) 和 \(m_i\) 互质。
最后 \(x=\sum a_ic_id_i\)。
3.2 ExCRT
任意 \(m_i\)。
核心思想是每次只合并 2 个方程。
首先对于 \(x\equiv a_1\pmod {m_1}\),有 \(x=k_1m_1+a_1\);代入第二个方程:\(k_1m_1+a_1=k_2m_2+a_2\)。
那么就有 \(k_1m_1-k_2m_2=a_2-a_1\),exgcd 求即可。
又一个问题,\(x\equiv a_1\pmod {m_1}, x\equiv a_2\pmod {m_2}\) 合并后,\(m\) 怎么变?结论:\(\operatorname{lcm}(m_1,m_2)\)。
所以新方程:\(x\equiv k_1m_1+a_1\pmod {\operatorname{lcm}(m_1,m_2)}\)。后面是个常数。
加入一个方程合并一次到最后就好了。
cin >> n >> b1 >> a1; bool flag = 1;
for(int i = 2, a2, b2;i <= n; ++i) {
b2 = read(), a2 = read(); if(!flag) continue ;
if((a2 - a1) % __gcd(b1, b2)) { flag = 0; continue ; }
int GCD = __gcd(b1, b2); int k = ((a2 - a1) % b2 + b2) % b2 / GCD;
int x; exgcd(b1 / GCD, b2 /= GCD, x, *new int); x = (x % b2 + b2) % b2;
x = (__int128)x * k % b2;
a1 += x * b1, b1 *= b2, a1 = (a1 % b1 + b1) % b1;
}
注意上面代码中 \(b\) 代表 \(m\)。
难绷。
3.3 例题
古代猪文
用费马小定理的话,发现模数是个偶数,搞不了。
所以把这个模数拆成多个质因子,每个单独求答案,最后 CRT 还原出来即可。
屠龙勇士
几乎板子?
预处理一下,然后就是多个 exgcd 的方程,变一下就是 excrt 了。记得和某个值取 max。
4.欧拉函数
4.1 定义
\(\varphi(n)\) 定义为 \([1,n]\) 中于 \(n\) 互质的数。
4.2 性质
4.2.1 性质一
若 \(p\) 为质数,则 \(\varphi(p)=p-1\)。
4.2.2 性质二
若 \(p\) 为质数,则 \(\varphi(p^k)=(p-1)p^{k-1}\)。
考虑 \([1,p^k]\) 中有多少个是 \(p\) 的倍数,减去即可,共 \(p^{k-1}\) 个。
4.2.3 性质三
若 \(a\) \(\bot\) \(b\),则 \(\varphi(ab)=\varphi(a)\times \varphi(b)\)。
4.2.4 性质四
若 \(a\mid b\),则 \(\varphi(ab)=a\times \varphi(b)\)。
3 和 4 可以感性理解。或者直接用 4.2.5 即可。
4.2.5 性质五
设 \(n\) 的唯一分解为:\(n=\prod\limits _{i=1}^k p_i^{c_i}\),则 \(\varphi(n)=n\times \prod\limits _{i=1}^k \dfrac{p_i-1}{p_i}\)。
反复用上面的性质证就可以了。
根据这个,可以根号地求出单个欧拉值。
4.2.6 性质六
\(\varphi(\dfrac{n}{d})=\sum\limits_{i=1}^n [\gcd(i,n)=d]\)。
考虑 \(\gcd(i,n)=d\) 的一个必要条件是 \(\dfrac{i}{d}\) \(\bot\) \(\dfrac{n}{d}\)。现在给定 \(n,d\),那么 \(i\) 的个数就是满足 \(\dfrac{i}{d}\) \(\bot\) \(\dfrac{n}{d}\) 的个数,即 \(\varphi(\dfrac{n}{d})\)。
4.2.7 性质七 欧拉反演
\(\sum\limits _{d\mid n} \varphi(d) = n\)。
首先 \(n=\sum\limits_{d\mid n}\sum\limits_{i=1}^n [(i,n)=d]\)。
根据性质六:\(n=\sum\limits_{d\mid n}\varphi(\dfrac{n}{d})=\sum\limits_{d\mid n}\varphi(d)\)。
4.2.8 性质八
对于 \(n>2\),\(2\mid \varphi(n)\)。
知道 \(x\bot n\),则 \(n-x\bot n\) 即可。
4.2.9 性质九
若 \(a\mid b\),则 \(\varphi(a)\mid \varphi(b)\)。
因为 \(b\) 包含了 \(a\) 的质因子,所以 \(p\) 那一坨的式子也满足整除关系。
4.3 线性筛欧拉函数
根据性质 3、4,再结合线性筛即可。
void init(int len) {
phi[1] = f[1] = 1;
for(int i = 2;i <= len; ++i) {
if(!f[i]) p[++cnt] = i, phi[i] = i - 1;
for(int j = 1;p[j] * i <= len and j <= cnt; ++j) {
f[p[j] * i] = 1; phi[i * p[j]] = phi[i] * (p[j] - 1);
if(i % p[j] == 0)
{ phi[i * p[j]] = p[j] * phi[i]; break; }
}
}
}
4.4 欧拉定理
5. 莫比乌斯函数
本身也没什么好讲的,主要是狄利克雷卷积那一部分。
5.1 性质
5.1.1
- \(\mu * 1 = \varepsilon\),即 \(\sum\limits _{d\mid n} \mu(d)=[n=1]\)。非常重要。
考虑证明:
将 \(n\) 的所有 \(c_i\ge 2\) 的质因子去掉,得到 \(n'\)。可知 \(\mu(n)=\mu(n')。\)
设 \(n'=\prod\limits _{i=1}^kp_i\),故 \(\mu(n')=\sum\limits _{i=0}^k \dbinom{k}{i}(-1)^i=(1-1)^k\)。
当 \(k=0\) 时特殊考虑,为 \(1\);其余恒为 \(0\)。
由此我们看出 \(\mu\) 大致就是 \(1^{-1}\)。
所以我们引出反演:
5.1.2
- 若 \(g=f*1\),则 \(f=g*\mu\)。
根据欧拉反演:\(\operatorname{id}=\varphi * 1\)。可知:\(\varphi = id * \mu\),即:
5.1.3
5.1.4
求 \(\large\sum\limits _{i=1}^n\sum\limits_{i=1}^m d(i\times j)\)。
引理:\(\large d(i\times j)=\sum\limits_{x\mid i}\sum\limits_{y\mid j}[\gcd(x,y)=1]\)
证明考虑钦定选 \(y\) 的前提要选完 \(x\) 中所有 \(y\) 里面的质因子。而选 \(x\) 中的质因子则一定不能选 \(y\),这样就一一对应。
然后就是一些应用。
6. ex:线性筛求积性函数(一般)
因为自己唐完了。
记录 \(g(n)=p_1^{c_1}\),其中 \(p_1\) 是 \(n\) 最小的质因子。(为什么记录 \(p_1\)?因为最先筛到,就这样)
当然,最开始 \(g(n)\) 最开始肯定 \(c_1\) 不对,需要动态更新。
然后可以根据积性函数性质更新了:
若 \(n=g(n)\),则 \(O(1)\) 直接计算即可;否则 \(f(n)=f(g(n))\times f(\dfrac{n}{g(n)})\)。
注意一点,若 \((x,y)\neq 1\) 则不能直接积。
Hint
对于一般情况,积性函数一定可以用线性筛。但是,部分普通函数也可以用线性筛。如:P2257。
在时间不卡的情况下,可以用埃氏筛轻松地求解任意函数,时间为 \(O(n\log\log n)\)。
SP5971
注意积性函数性质:若 \(f\) 为积,则 \(f*1\) 也为积。
我们要求 \(g=f*1\),即 \(g(n)=\sum\limits _{d\mid n}f(d)\),那么 \(g\) 也满足积性函数性质。
这里 \(f(n)=n\varphi(n)\),显然是积。
注意上文有一个式子:
后面那一坨要记得加上,然后 \(g(n)\) 计算时注意 \(d=1\)。