数论分享
数论选讲
--数论是数学的皇后--
写在废话之前
HL 集训的时候,某场模拟赛 T2 放了一个欧拉函数相关的题目,然后当场比赛获得了 \(100\)pts \(+0\)pts \(+0\)pts \(+0\)pts \(=100\) pts 的优异成绩。
细说这场模拟赛的的感受的话,可能云落能讲一个多小时,显然时间并不应该被消耗在这个上面。
不过云落还是对 T2 的欧拉函数耿耿于怀,所以有了后面的数论专项突击,也促成了今天的数论分享。
废话
根据过往云落学习数论的经验来看,这个学习过程是相当枯燥乏味的。反正如果诸位有数学公式恐惧症的话,不建议一次性食用过多。
下一张 PPT 会展示目录,难度是升序排序的,这边建议诸位根据自身情况,选择性或者有方法地听(不建议直接 \(z^{z^z}\))。
知识点基本上会很快过掉,如果需要知识点讲解建议出门左转去 oi.wiki 查阅资料。
里面的例题都是云落做过或者口胡过的好题,拿出来讲解。
云落年岁不小了,剩余的时间需要云落去争分夺秒了。所以云落组织了这次分享是带有很大私心的。在准备的过程中,云落获益良多,也希望可以收益最大化,把这些寄存在云落脑子里的东西展示出来。所以云落希望可以在数论这个方面,邀诸位共赏。
废话结束,正片开始。
目录
-
基础知识
-
数论分块
-
筛法与欧拉(积性)函数
-
费马小定理、欧拉定理、扩展欧拉定理
-
逆元及其线性求法
-
二元一次不定方程、线性同余方程、线性同余方程组
-
卢卡斯定理
数论基础
整除?应该 0 个人不会吧!
约数、倍数、质数、合数,不会的可以立刻退役了……
gcd 与 lcm
- 随机抽个人默写一下辗转相除法的代码,顺便说一下 gcd 与 lcm 的数量关系。
同余
- 可加性,可减性,可乘性,可乘方性(思考:为什么没有可除性?)。
分解质因数
- 抽个人说一下时间复杂度。
例题
No.1
给定正整数 \(L,R(1 \le L \le R \le 2 \times 10^9 ,\ R-L \le 10^6)\),求 \([L,R]\) 内质数个数。
No.2
记正整数 \(x\) 的约数个数为 \(g(x)\),一个数是好的当且仅当 \( \forall i \in [1,x-1] ,\ g(x)>g(i)\)。给定 \(n(n \le 2 \times 10^9)\),求最大的 \(\le n\) 的好数。(高效进阶贴贴)
题解
No.1
线性筛没有前途,寄。合数 \(x\) 总是存在 \(\le \sqrt{x}\) 的因子,所以可以先把 \(\sqrt{R}\) 范围内的质数筛出来,再用质数标记 \([L,R]\) 范围内的合数,完结撒花。
No.2
对好数质因数分解成如下形式 \({p_1}^{k_1} \times {p_2}^{k_2} \dots \times {p_m}^{k_m}\),一定有 \(k\) 单调不升,否则你总能找到约数个数与之相同的但数值更小的数,与好数定义矛盾。
在 \([1,2 \times 10^9]\) 范围内,一个数最多分解出 \(11\) 个质因子,所以可以直接开搜了,也可以打表,条条大路通罗马。
数论分块
先来到例题练练手——
给定 \(n(1 \le n \le 10^6)\),求 \(\sum_{i=1}^{n} \lfloor \frac{n}{i} \rfloor\) 的值。
哦,基础循环语句练习题。
简单修改一下数据范围,现在要求 \(1 \le n \le 10^{12}\),咋做?
需要用到大名鼎鼎的数论分块。
如果你手模能力很强,你就会发现把 \(\big\lfloor \frac{n}{i} \big\rfloor\) 丢到一个序列上,取值相同的部分在序列上会形成连续段的形式。
然后你又发现这些取值构成的集合,集合大小不会超过 \(2 \sqrt{n}\)。
数论分块
出现了神秘的根号状物,所以做上面这个题就需要去往根号上面靠一靠。
记 \(l\) 为分块左边界,记这个块的值为 \(k\),则 \(k=\big\lfloor \frac{n}{l} \big\rfloor\)。显然这个块的有边界 \(r\) 是最大的 \(\le \frac{n}{k}\) 的位置,将 \(k\) 代入后也就是 \(\Big\lfloor \frac{n}{\lfloor \frac{n}{l} \rfloor} \Big\rfloor\)。
核心代码:
inline ll solve(ll n){
ll l=1,r=0,res=0;
while(l<=n){
r=n/(n/l);
res+=n/l*(r-l+1);
l=r+1;
}
return res;
}
若干思考题
No.1
给定 \(n(n \le {10}^{12})\),求满足 \(ab,ac,bc\) 均 \(\le n\) 的有序三元组 \((a,b,c)\) 个数。
No.2
记 \(g(x)\) 表示 \(x\) 的约数个数,给定 \(L,R(1 \le L \le R \le 10^9)\),求 \(\sum_{i=L}^{R} g(i)\)。
No.3
计算:
其中正整数 \(n,m\) 满足 \(1 \le n,m \le 10^9\)。
题解
No.1
记 \(B=\big\lfloor \sqrt{n} \big\rfloor\)。
-
若 \(a,b,c \le B\),则对答案的贡献是 \(B^3\)。
-
若 \(a > B\),由题意,\(b,c \le B\),所以枚举 \(a\),贡献形如:
变成数论分块板板题咯!
有序三元组,答案还得 \(\times 3\),因为 \(b,c\) 都有可能成为 \(>B\) 的那个“幸运儿”。
题解
No.2
首先把区间问题转化为前缀问题,最后差分一下
容易发现,正整数 \(i\) 在 \([1,n]\) 范围内作为约数出现的次数为 \(\big\lfloor \frac{n}{i} \big\rfloor\)。那么,对于约数 \(i\),约数和贡献形如 \(i \times \big\lfloor \frac{n}{i} \big\rfloor\)
那么一个前缀 \([1,n]\) 的答案应当是如下形式:
数论分块告诉我们,在同一个块内,\(\big\lfloor \frac{n}{i} \big\rfloor\) 的值总是相同的。因此,在同一个块内,只需要考虑 \(\sum i\) 的值即可,显然可以 \(O(1)\) 计算。
题解
No.3
先推式子……记原式为 \(ans\)
推到这里还不会做就回炉重造叭!
筛法与欧拉(积性)函数
埃氏筛
-
怎么写?
-
时间复杂度?
线性筛,又称欧拉筛
- 比埃氏筛快在哪里?
欧拉函数
- 一些重要结论?
埃氏筛
从小到大枚举,判定质数的条件是当枚举到这个数的时候,它没有被标记为合数。
什么时候会被标记为合数?当出现一个质数 \(p\) 的时候,标记所有的 \(i \times p\) 为合数。
时间复杂度 \(O(n \log \log n)\)。
bool isprime[N];int prime[N],tot;
inline void eratos(){
memset(isprime,true,sizeof(isprime));
isprime[1]=false;
for(int i=2;i<=n;i++){
if(!isprime[i])continue;
prime[++tot]=i;
for(int j=i*i;j<=n;j+=i)isprime[j]=false;
}
return;
}
线性筛
当合数被筛掉的时候,我们希望他只被筛一次,所以……
bool isprime[N];int prime[N],tot;
inline void euler(){
memset(isprime,true,sizeof(isprime));
isprime[1]=false;
for(int i=2;i<=n;i++){
if(isprime[i])prime[++tot]=i;
for(int j=1;j<=tot&&i*prime[j]<=n;j++){
isprime[i*prime[j]]=false;
if(i%prime[j]==0)break;// 保证复杂度的关键语句捏!
}
}
return;
}
时间复杂度 \(O(n)\)。
欧拉函数
一起来康康欧拉函数的相关性质:
-
\(\varphi(x)\) 是积性函数(不是完全积性函数)。
-
对于任意的质数 \(p\),\(\varphi(p)=p-1\)。
-
对于任意的质数 \(p\),\(\varphi(p^k)=p^k-p^{k-1}\)。
-
\(\sum\limits_{d|n} \varphi(d) = n\)。
欧拉函数
啥子是积性函数?啥子是完全积性函数?
-
积性函数:若函数 \(f(n)\) 满足 \(f(1)=1\),且 \(f(xy)=f(x)f(y)\) 对任意互质的 \(x,y \in \mathbf{N}^*\) 都成立,则 \(f(n)\) 为积性函数。
-
完全积性函数:若函数 \(f(n)\) 满足 \(f(1)=1\),且 \(f(xy)=f(x)f(y)\) 对任意的 \(x,y \in \mathbf{N}^*\) 都成立,则 \(f(n)\) 为积性函数。
欧拉函数
对上面几个性质弄一些简单的证明(告别 OI,走向数竞)。
- 对于任意的质数 \(p\),\(\varphi(p)=p-1\)。
证明:显然只有 \(p\) 本身与 \(p\) 不互质,所以是 \(p-1\)。
- 对于任意的质数 \(p\),\(\varphi(p^k)=p^k-p^{k-1}\)。
证明:注意到与 \(p^k\) 不互质的数只有 \(p,2p,3p,\dots,p^{k-1}p\),共计 \(p^{k-1}\) 个,所以与 \(p^k\) 互质的有 \(p^k-p^{k-1}\) 个。
推广:对于任意的 \(x\),根据唯一分解定理,即 \(x=\prod p_i^{k_i}\),\(\varphi(x)=x \prod (1-\frac{1}{p_i})\)。
剩下俩不证了,积性函数那个可以容斥原理结合上面这个推广简单证明;带求和号的那个,重点在于证明那个式子也是积性函数。感兴趣的可以自己尝试一下。
欧拉函数
单次 \(O(n)\) 或者 \(O(\sqrt{n})\) 求 \(\varphi\) 的朴素暴力做法还是太笨拙了,欠优化。
筛法它本来就不是只用于筛质数的,筛法可以快速解决一些积性函数的求值问题。
bool isprime[N];int prime[N],tot,phi[N];
inline void euler(){
phi[1]=1;
memset(isprime,true,sizeof(isprime));
isprime[1]=false;
for(int i=2;i<=n;i++){
if(isprime[i])prime[++tot]=i,phi[i]=i-1;
for(int j=1;j<=tot&&i*prime[j]<=n;j++){
isprime[i*prime[j]]=false;
if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}
phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
return;
}
欧拉函数
初始化 phi[1]=1
不多赘述。
代码里有三个部分是计算 phi
的,一三都比较显然,就是前面的重要结论。
第二个部分需要简单推一下(需要用到前面的“推广”)……
因为 i%prime[j]==0
,所以后面的 \(\prod\) 不会出现少乘一项的情况,美滋滋。
例题
No.1
给定 \(n(1 \le n \le 10^7)\),求 \(1 \le x,y \le n\) 且 \(\gcd(x,y)\) 为质数的 \((x,y)\) 的数目。
No.2
给定一个正整数 \(n\),每次操作形如 \(n \gets \varphi(n)\),问至少多少次操作之后 \(n=1\)。注意:\(n\) 以唯一分解的形式给出,即:
数据范围:\(1 \le m \le 2000 ,\ 1 \le p_i \le 10^5 ,\ 1 \le q_i \le 10^9\)。
题解
No.1
抽象成式子,大概长下面这个样子:
典中典之枚举 \(\gcd\),上式化为:
对于 \(i,j\) 的两层枚举来说,\(d\) 是一个定值,所以直接转化为 \(i,j\) 互质的情况,即:
你发现后面这坨是有序对,直接改变 \(j\) 的枚举上界转成无序对最后在 \(\times 2\),也就是:
对于这个式子,把 \(2\) 提出去,然后就是 \(\varphi(i)\) 咯!式子如下:
线性筛出来 \(\varphi\) 值,再做一个前缀和预处理,剩下的交给基础循环语句即可。
时间复杂度 \(O(n)\)。
题解
No.2
先来看看一次操作所带来的影响是什么。
这式子不可看,把一些邪恶的分母干掉,有:
你注意到这个式子告诉你,一次操作相当于对于所有的质因子,每种挑选一个 \(-1\) 之后再和原来的部分累乘合并。
还有一个观察,对于方程 \(\varphi(x)=1\),方程只有两个解 \(x_1=1,x_2=2\)。
然而 \(\times 1\) 是没有任何影响的,所以操作次数等价于整套流程中质因子 \(2\) 的出现次数。
那么,除了一开始分解出来的 \(2\) 以外,还有什么东西会生产 \(2\)?
自然就是 \(p_i-1\) 的部分,它们会在下一次操作时参与分解。
因此,考虑 DP。记 \(f_i\) 表示自然数 \(i\) 能在整套分解流程中生产的 \(2\) 的数量。
转移有两种,简单分讨一下:
-
\(i\) 是质数,显然 \(f_i=f_{i-1}\);
-
\(i\) 不是质数,令 \(xy=i\),则 \(f_i = f_x + f_y\)。
这是一个经典的加性函数,可以在线性筛的时候求出来。
其实到这里差不多了,由于上面 \(p_i\) 上面还挂着一个 \(q_i\),所以答案是 \(\sum{f_{p_i} \times q_i}\)。
然而,这么写的话 WA 将是你的归宿。
corner case 就是 \(n\) 不包含质因子 \(2\),也就是说第一轮不会消耗 \(2\),需要多操作一轮。
核心代码:
inline void euler(int n){
f[1]=1;
for(int i=2;i<=n;i++){
if(!isprime[i])prime[++tot]=i,f[i]=f[i-1];
for(int j=1;j<=tot&&i*prime[j]<=n;j++){
isprime[i*prime[j]]=true;f[i*prime[j]]=f[i]+f[prime[j]];
if(i%prime[j]==0)break;
}
}
return;
}
费马小定理、欧拉定理、扩展欧拉定理
费马小定理:对于质数 \(p\) 和正整数 \(a\) 且 \(p \nmid a\),有 \(a^{p-1} \equiv 1 \pmod{p}\)。
欧拉定理:对于正整数 \(a,m\) 且 \(\gcd(a,m)=1\),有 \(a^{\varphi(m)} \equiv 1 \pmod{m}\)。
扩展欧拉定理:
对于任意正整数 \(a,m\) 和自然数 \(k\) ,有:
根据扩展欧拉定理,我们可以解决指数较大的模意义下计算。具体地,按上式第三种情况反复缩小规模,直到满足第二种情况,快速幂计算。这个行为又称欧拉降幂。
证明
这一部分与 OI 相去甚远,感兴趣的可以自行阅读。
欧拉定理的证明
我们对模数 \(m\) 取出 \([1,m-1]\) 范围内所有与它互质的数,记作 \(b_1,b_2,\dots,b_{\varphi(m)}\)。
推论:定义 \(A_i = ab_i \bmod m\),序列 \(A\) 中所有元素均与 \(m\) 互质且两两不同。
推论的证明:考虑反证法。
假设存在 \(ab_i \equiv ab_j \pmod{m}\),则一定有 \(a(b_i-b_j) \equiv 0 \pmod{m}\)。
因为 \(\gcd(a,m)=1\),故 \(b_i-b_j \equiv 0 \pmod{m}\),即 \(b_i \equiv b_j \pmod{m}\)。
这与当初的 \(b\) 序列的定义是矛盾的,故假设不成立,结论得证。
所以 \(A\) 中的每个元素一定与 \(b\) 中的一个数同余,且一一对应。
根据以上推理,可以写出如下式子:
取一三两部分,移项得:
聪明的你一定发现了,因为 \(\gcd(b_i,m)=1\),所以有:
最后一步再移一下项,宣告撒花。
费马小定理的证明
方才已经证明了欧拉定理,所以欧拉定理可以直接食用。
将质数 \(p\) 代入欧拉定理中,有:
众所周知 \(\varphi(p)=p-1\),所以嘛——
\(Q.E.D.\)
花絮:现在知道指数上这个稀奇古怪的 \(p-1\) 是怎么一回事了吧……
扩展欧拉定理的证明
\(\texttt{case 1}\)
考虑把指数 \(k\) 拆分为 \(b \times \varphi(m) + k \bmod \varphi(m)\)。
具体地,按下面推式子:
根据欧拉定理 \(a^{\varphi(m)} \equiv 1 \pmod{m}\),有:
结论得证了捏,撒花!
\(\texttt{case 2}\)
正确性显然,无需证明。
\(\texttt{case 3}\)
原命题充要转化:对于 \(a\) 中质因子 \(p\),满足 \(p^k \equiv p^{(k \bmod \varphi(m)) + \varphi(m)} \pmod{m}\)。
充要转化的正确性显然,考虑 \(a\) 的唯一分解,结合余数的可乘性和可乘方性可以简单证明,这里不多赘述。
若 \(p,m\) 互质,转化为 \(\texttt{case 1}\);否则 \(\gcd(p,m) \neq 1\),由于 \(p\) 是质数,则 \(p \mid m\)。
经典操作之令 \(m=s \times p^r\),其中 \(\gcd(s,p)=1\),显然有 \(\varphi(m) = \varphi(s) \times \varphi(p^r)\)。
把 \(\varphi(m) = \varphi(s) \times \varphi(p^r)\) 代入,结合欧拉定理 \(p^{\varphi(s)} \equiv 1 \pmod{s}\),有:
两边同时乘 \(p^r\) 得:
显然有 \(k \ge \varphi(m) \ge r\)(不是,这显然吗?)
根据上页最后一个式子,有如下推理:
然后搞点高一数学,设定义在 \([\varphi(m),+\infty)\) 的函数 \(f(x)\) 满足 \(f(x)=p^x \bmod m\)。
根据上式,当 \(x \ge \varphi(m)\) 时,有 \(f(x)=f(x+\varphi(m))\)。进一步地,当 \(x \ge 2 \varphi(m)\) 时,有 \(f(x)=f(x-\varphi(m))\)。
容易发现,\(f(x)=f((x \bmod \varphi(m)) + \varphi(m))\),代入 \(x=k\),有
\(Q.E.D.\)
例题
费马小定理在 oi 中最经典的应用还是逆元,所以咱们弄一点欧拉定理的好东西。
No.1
无穷序列 \(a\) 满足 \(a_0=1,a_n=2^{a_{n-1}}\)。给定一个正整数 \(m(1 \le m \le 10^7)\),可以证明 \(b_n=a_n \bmod m\) 在某一项后都是同一个值,求这个值。
No.2
给定一个序列长度为 \(n(1 \le n \le 10^5)\) 的序列 \(a\) 和正整数 \(m(1 \le m \le 10^9)\),\(q(1 \le q \le 10^5)\) 次查询区间 \([l,r]\),求 \({a_l}^{{a_{l+1}}^{{\cdots}^{a_r}}} \bmod m\) 的值。
题解
No.1
指数一层一层递归掉,欧拉降幂。降幂过程中需要多次求 \(\varphi\),线性筛预处理即可。
No.2
欧拉降幂显然,但时间复杂度 \(O(nq\log V)\),因为一次降幂只能干掉 \(O(1)\) 个数。
注意到有效的降幂层数不多,每次降幂相当于给模数不断复合 \(\varphi\),又有 \(\varphi(1)=1\)。
根据欧拉函数的性质,可以断言最多降幂 \(O(\log q)\) 次。
- 当 \(x>2\) 时,\(\varphi(x)\) 是偶数;
- 当 \(x\) 是偶数时,\(\varphi(x) \le \frac{x}{2}\)。
上述性质显然,断言成立,时间复杂度 \(O(q \log n \log V)\)。
逆元及其线性求法
单个逆元求法
-
质数?快速幂(费马小定理)
-
任意一数?逆元存在就扩展欧几里得,否则就不存在呗。
多个逆元求法
-
质数?抽个人报一下式子。
-
任意多数?前缀积,然后逆元性质了解一下。
抓一个幸运儿,依次报一下上面每种做法的时间复杂度。
例题
No.1
给出长度 \(n\) 的序列 \(a\),\(q\) 次询问 \(\prod_{i=l}^{r} \text{lcm} (a_i,x)\) 的值(所有变量均在 \([1,10^5]\) 内)。
No.2
luogu P2054
题解
(题解被云落给咕掉了)
第一个题需要推式子,不想码 latex。
第二个题是拍脑袋题,不知道各位有没有拍脑袋拍出来。
题解
开玩笑的,云落还是会写题解的,就是第一个题 latex 有点扭曲,给诸位先打个预防针。
No.1
查询 \(\text{lcm}\) 可以转化为 \(\gcd\),需要维护一个 \(x\) 的幂和区间积,快速幂和前缀积搞定。
现在问题转化为,在合理的时间复杂度内,求下列式子的值。
推式子肯定是要推的,诸位可以简单思考一下,有哪些推式子的 trick。
唉,质因数唯一分解在数论中的地位还是太举足轻重了。
考虑分别对 \(a_i,x\) 质因数分解,记原式结果为 \(A\),有:
这个式子的实际含义等价于对于每个质因子,求区间内可以分解出该质因子的数目。
不需要任何神秘的数据结构,只需要一个小小的 vector
加一个小小的二分即解决。
具体地,对于每个质因子 \(p\) 的 \(t\) 次幂 \(p^t\),我们用 vector
维护所有以 \(p^t\) 为约数的 \(a_i\) 的下标 \(i\)。查询的时候直接在 vector
上二分 \(l,r\) 的位置。
代码上还有很多细节,云落后面会结合代码来说。
时间复杂度 \(O(q \log n \log V)\)。
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>q;
for(int i=1;i<=n;i++)cin>>a[i];
euler(N-5);init();
while(q--){
int l,r,x;cin>>l>>r>>x;
int ans=mul[r]*qpow(mul[l-1],MOD-2)%MOD*qpow(x,r-l+1)%MOD;
while(x>1){
int t=d[x],p=1,sum=0;
while(x%t==0){
x/=t,p*=t;
auto L=lwbd(vec[p].begin(),vec[p].end(),l),R=upbd(vec[p].begin(),vec[p].end(),r);
sum+=(R-L);
}
ans=ans*(qpow(qpow(t,sum),MOD-2)%MOD)%MOD;
}
cout<<ans<<'\n';
}
return 0;
}
inline void euler(int n){
memset(isprime,true,sizeof(isprime));
isprime[1]=false;
for(int i=2;i<=n;i++){
if(isprime[i])prime[++tot]=i,d[i]=i;
for(int j=1;j<=tot&&i*prime[j]<=n;j++){
isprime[i*prime[j]]=false;d[i*prime[j]]=prime[j];
if(i%prime[j]==0)break;
}
}
return;
}
inline void init(){
mul[0]=1;
for(int i=1;i<=n;i++)mul[i]=mul[i-1]*a[i]%MOD;
for(int i=1;i<=n;i++){
int x=a[i];
while(x>1){
int t=d[x],p=1;
while(x%t==0)x/=t,p*=t,vec[p].pb(i);
}
}
return;
}
题解
No.2
开始手模,假设初始牌序是 \(\{1,2,3,4,5,6\}\),接下来展示若干轮洗牌后的牌序。
- 第一轮洗牌后:\(\{4,1,5,2,6,3\}\);
- 第二轮洗牌后:\(\{2,4,6,1,3,5\}\);
- 第三轮洗牌后:\(\{1,2,3,4,5,6\}\)。
你发现:假设洗牌前的位置为 \(x\),则一轮洗牌后的位置为 \(2x \bmod (n+1)\)。
容易想到,答案就是同余方程 \(2^m \times x \equiv l \pmod{n+1}\) 的解,计算 \(2^m\) 在模 \(n\) 意义下的乘法逆元就行了嘛!
二元一次不定方程、线性同余方程、线性同余方程组
在上一道题目的渗透下,我们已经初步触摸到和数论有关方程的门槛了。
开始方程之旅之前,必然要知悉裴蜀定理。
裴蜀定理:对于正整数 \(a,b\),对于任意的 \(x,y\) 都有 \(\gcd(a,b) \mid ax+by\)。特别地,一定存在一组 \(x,y\),使得 \(\gcd(a,b)=ax+by\) 成立。
重要推论:正整数 \(a,b\) 互质的充要条件是存在整数 \(x,y\) 使得 \(ax+by=1\)。
好的,你已经学会了最重要的东西,接下来请你分别求出下列不定方程中 \(x,y\) 的一组整数解(或报告无解),其中 \(a,b,c\) 都是给定的正整数。
这个时候 exgcd 闪亮登场,exgcd 可以解决 \(ax+by=\gcd(x,y)\) 的一组整数解。
二元一次不定方程、线性同余方程、线性同余方程组
象征性意义的贴一下 exgcd 的模板……
inline int exgcd(int a,int b,int &x,int &y){
if(b==0){x=1,y=0;return a;}
int d=exgcd(b,a%b,x,y);
int tmp=x;
x=y,y=tmp-a/b*y;
return d;
}
- \(c\) 不是 \(\gcd(a,b)\) 的倍数就直接无解;
- 用 exgcd 解出一组 \(x,y\),然后分别乘上 \(\frac{c}{\gcd(a,b)}\) 得到原方程的一组特解;
- 于是乎就没有然后了(要是求最小正整数解之类的东西,可以接着往下推,找到通解形式即可)。
二元一次不定方程、线性同余方程、线性同余方程组
那么,我们跑步前进,来看线性同余方程,其形式如下:
转化一下,这个线性同余方程等价于不定方程——
好的,回到原来的问题上去了,直接 exgcd 即可。
当然从逆元的角度来理解也是可以的,只不过未保证 \(m\) 是质数,还得落到 exgcd 上。
例题
高效进阶已经急不可耐了,放两道高效进阶进来。
No.1
给定 \(n\) 元环,环上有两动点 \(A,B\)。动点 \(A,B\) 初始分别在 \(x,y\) 上,并即将顺时针移动。移动定义为在原地消失,在远方刷新。动点 \(A,B\) 的单次移动距离分别是 \(d1,d2\)。问两动点同时在某个位置上刷新的最少时间(或报告永远无法同时刷新在同一位置)。
No.2
luogu P2421
(这俩题不写题解了,都比较板子)
二元一次不定方程、线性同余方程、线性同余方程组
问:有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?
答:三人同行七十希,五树梅花廿一支,七子团圆正半月,除百零五便得知。
古老而神秘的华夏,孕育出了解决线性同余方程组的方法——中国剩余定理。
放一个线性同余方程组的标准形式。
上面的「物不知数」问题就是一元线性同余方程组的一个实例。
二元一次不定方程、线性同余方程、线性同余方程组
先讲 CRT,要求模数上两两互质。
-
计算所有模数的积 \(M\);
-
对于第 \(i\) 个同余方程,分三步;
- 计算 \(b_i=\frac{M}{m_i}\);
- 计算 \(b_i\) 在模 \(m_i\) 意义下的逆元 \({b_i}^{-1}\);
- 计算 \(c_i=b_i{b_i}^{-1}\);
- 解得 \(x \equiv \sum_{i=1}^{k}a_ic_i \pmod{M}\)。
这没什么可解释的,证明起来比较复杂,直接背就行了……
建议打个板子,当 exgcd 的练手题。
二元一次不定方程、线性同余方程、线性同余方程组
重点是 excrt,没有什么更多的条件限制,而且思路也更符合人类惯性思维一些。
excrt 的核心思想就是把两个同余方程捏成一个同余方程,给一些数学上的推导。
同余方程不好看,还是先归约到不定方程的形式,如下:
然后干掉未知数 \(x\),获得关于 \(m,n\) 的不定方程,即:
二元一次不定方程、线性同余方程、线性同余方程组
上页最后一个式子显然是一个不定方程的基本形式,exgcd 可以简单获取这个不定方程的一组特解 \((m',n')\)(或报告无解)。把 \(m'\)(或 \(n'\))代回到最初的不定方程组中,可以获取一个 \(x\) 的特解 \(x=x'\)。
现在问题在于,如何通过 \(x=x'\) 这一特解反向推出合并后的同余方程?
注意到两个同余方程的模数分别是 \(A,B\),所以可以发现,若 \(x=x'\) 是原方程组的一个特解,那么 \(x=x'+\text{lcm}(A,B)\) 也一定是一个合法的特解。
进一步地,\(x=x'+k \times \text{lcm}(A,B)\) 一定是 \(x\) 的通解表现形式。
这样我们只需要把上面这个通解写成同余的形式即可,形如:
综上所述,我们完成了两个同余方程的合并,也就能解线性同余方程组了。
二元一次不定方程、线性同余方程、线性同余方程组
代码展示(模板题需要开 __int128
防止乘法溢出)
inline ll exgcd(ll a,ll b,i2 &x,i2 &y){
if(b==0){x=1,y=0;return a;}
ll d=exgcd(b,a%b,x,y);i2 tmp=x;
x=y,y=tmp-a/b*y;
return d;
}
signed main(){
cin>>n>>A>>a;
for(int i=2;i<=n;i++){
ll B,b;cin>>B>>b;
ll g=exgcd(A,B,x,y),lcm=A/g*B;
i2 m=(i2)((b-a)/g*x),x0=A*m+a;
a=(x0%lcm+lcm)%lcm,A=lcm;
}
cout<<a<<'\n';
return 0;
}
例题
No.1
luogu P3868
(这个题找个人直接报做法吧……)
No.2
\(r \times c (1 \le r,c \le 10^6)\) 的二维平面上有一动点在 \((0,0)\) 处。一行命令形如长度为 \(n(1 \le n \le 10^6)\) 的字符串。字符只包含 U
、D
、L
、R
,分别表示上下左右移动,每次动点只会按命令方向平移一格。若执行当前命令会越界,则将整个命令行中所有和当前命令相同的命令方向扭转 \(180 \degree\),命令行要重复执行 \(k(1 \le k \le 10^{12})\) 次,求所有命令执行结束之后,这个动点会经过多少次 \((0,0)\)?
题解(No.2 sol)
命令扭转一眼不想什么好东西,而且数据范围奇大,不可模拟。
结论:如果不进行命令扭转,那么其新的横纵坐标 \((x',y')\) 和正常执行命令的横纵坐标 \((x,y)\) 一定满足:
这启示我们可以直接忽略命令扭转的环节,在原命令上做就 OK 了。并且这个同余的限制保证了有效的活动范围并不是很大。
但是,答案怎么算捏?
题解(No.2 sol)
无法枚举路径依旧是个问题,然而命令行是反复出现的,这给予我们优化的空间。
先考虑单次命令行我们怎么做,显然是直接模拟,回到 \((0,0)\) 直接 ans++
就做完了。
重复多次咋办?你发现可以维护单次命令行的偏移量(横 \(\Delta x\) 纵 \(\Delta y\)),然后知晓重复 \(t\) 次就可以求出总偏移量(横 \(t \cdot \Delta x\) 纵 \(t \cdot \Delta y\))。
对于出现在第 \(t+1\) 组命令行中的第 \(i\) 条命令,若它可以贡献给答案,则一定满足:
其中 \(X_i,Y_i\) 分别表示执行完前 \(i\) 条命令的横纵坐标偏移量。
题解(No.2 sol)
起猛了,看见方程组了。
再揉揉眼睛,啧,好像还是同余方程组。
那直接 excrt 把同余方程二合一,然后把新的同余方程的通解形式求出来之后,\(O(1)\) 计算 \(k\) 范围内的整数解的个数。
卢卡斯定理
跑步前进,先说定理。
对于素数 \(p\),有:
其中当 \(n<k\) 时,二项式系数 \({n \choose k}\) 规定为 \(0\)。
你发现这是一个递归的形式,因为 \({\lfloor \frac{n}{p} \rfloor \choose \lfloor \frac{k}{p} \rfloor}\) 可以继续进行卢卡斯定理直到可以计算。
因此,我们只需要计算 \({{n\bmod p} \choose {k\bmod p}}\) 即可。
这对 \(p\) 的规模有一定的要求,显然不能够是 \(998244353\) 之类的大质数。
尽管有一定的局限性,但是依旧大大的好用!
例题
No.1
高效进阶稳定发挥。
计算 \(g^{\sum_{d \mid n} {n \choose d}} \bmod 999911659\)。
数据范围:\(1 \le n,g \le 10^9\)。
No.2
只能向右下方向跳跃的马。初始位置 \((0,0)\),目标位置 \((n,m)\)。有 \(k\) 个障碍物(不存在蹩马腿),求方案数对 \(10007\) 取模的值。
题解
No.1
终于等到你了古代猪文,数论全家桶说的就是你!
STEP 1 扩展欧拉定理
可以把这个东西先套一层扩展欧拉定理,为了方便表述记 \(A=\sum_{d \mid n} {n \choose d}\),用 \(ans\) 表示式子的值,则有:
STEP 2 费马小定理
显然下面这个次方的东西可以费马小定理快速做,问题在于求解 \(A \bmod 999911658\)。
STEP 3 扩展中国剩余定理
就这么个模数,不是质数什么都是白搭,所以质因数分解之后写成同余方程组的形式。
温馨提示:\(999911658=2×3×4697×35617\)。
具体地,记 \(x\) 表示 \(A \bmod 999911658\) 的结果,有:
excrt 可以直接合并同余方程组,现在问题就转化为:求 \(A\) 在单个同余方程中的取值。
STEP 4 卢卡斯定理
组合数?还是取模?质数不超过 \(4 \times 10^4\)?卢卡斯定理直接安排上,完结撒花!
题解
No.2
记 \(f_{i,j}\) 表示跳跃到 \((i,j)\) 的方案数,显然 \(f_{i,j}\) 不为 \(0\) 的一个必要条件是 \(3 \mid i+j\)。
设跳了 \(a\) 次 \((+1,+2)\),跳了 \(b\) 次 \((+2,+1)\)。若 \(a<0\) 或者 \(b<0\),则 \(f_{i,j}=0\)。
考虑 DP,记 \(dp_i\) 表示到第 \(i\) 个障碍物前不碰到任何一个障碍物的方案数,答案是:
转移方程也很好去写,形如:
问题转化为快速求 \(f_{i,j}\),如果有值,显然 \(f_{i,j}={a+b \choose b}\),模数较小,上卢卡斯定理。
转场
以上内容难度介于 Div2 和 Div1 之间,接下来简单 level-up 一下。
可能会涉及一些稍微困难的算法与知识点,诸位量力而行。
目录
-
离散对数与 BSGS
-
狄利克雷卷积与莫比乌斯反演
-
杜教筛
-
杂《》选吃
离散对数与 BSGS
你无需知道离散对数的具体定义,你只需知道你需要一个高效的算法解决下面的问题。
给定正整数 \(a,b,m\),保证 \(\gcd(a,m)=1\),解同余方程:
引入一个算法——BSGS,其可以在 \(O(\sqrt{m})\) 的时间复杂度内解决这个问题。
进一步地,如果 \(\gcd(a,m) \neq 1\),可以使用 exBSGS,时间复杂度也是 \(O(\sqrt{m})\)。
离散对数与 BSGS
解决 \(a^x \equiv b \pmod{m}\) 的朴素做法是 \(O(m)\) 的。根据欧拉定理,\(x\) 所有的合法解中最小的那一个应当是 \(\varphi(m)\),所以是线性复杂度。
显然如果 \(m=998244353\),这种依据欧拉定理的暴力枚举就没有前途了。
注意到其实同余号右边的 \(b\) 没有起到任何作用。上面的朴素做法相当于 \(O(n)\) 预处理,然后 \(O(1)\) 判断。
像这种信息比对的东西,明显可以通过移项和哈希表的方式进行复杂度平衡。
比如求 \(a_x+a_y=C\) 的合法 \((x,y)\) 个数,除了暴力枚举 \(x,y\),还可以把 \(C-a_y\) 的所有值塞到哈希表里,然后用 \(a_x\) 去查询。
离散对数与 BSGS
这启发我们对 \(a^x \equiv b \pmod{m}\) 中的指数 \(x\) 动一些手术。
具体地,可以令 \(x=pc-q\),\(c\) 是由你决定的常数,于是有:
然后可以暴力枚举 \(q\),把所有 \(ba^q \bmod m\) 的取值丢到哈希表里面;再去暴力枚举 \(p\),把 \(a^{pc} \bmod m\) 的值放在哈希表里面查询。
显然以上算法一定是有正确性保证的。
当然,这里的 \(q\) 不应该大于 \(c\),而 \(p\) 的上界是 \(\frac{m}{c}\)。
因此,\(O(c)\) 枚举 \(q\),\(O(\frac{m}{c})\) 枚举 \(p\),总时间复杂度为 \(O(c+\frac{m}{c})\)。
根据均值不等式,容易发现 \(c\) 取到 \(\sqrt{m}\) 的时候 \(O(c+\frac{m}{c})\) 取到最小值,为 \(O(\sqrt{m})\)。
离散对数与 BSGS
exBSGS 在 BSGS 基础上多了几步前置转化,可以用于解决 \(\gcd(a,m) \neq 1\) 的问题。
高端的问题往往只需要最简单的解决方式,既然他们不互质,就一直除到它互质即可。
取 \(d_1=\gcd(a,m)\),如果 \(b \bmod d_1 \neq 0\),则原方程一定无解,否则等价转化为:
如果 \(a,\frac{m}{d_1}\) 依旧不互质,就取出 \(d_2=\gcd(a,\frac{m}{d1})\),重复执行上述操作。
跳出循环后,同余方程应该有如下形式:
简单做就好了,可以证明前面不断除以 \(d\) 的操作不能够成为时间复杂度瓶颈。
例题
给定正整数 \(k\) 和质数 \(m\),求最小正整数 \(n\),有 \(11 \cdots 1\)(\(n\) 个 \(1\))\(\equiv k \pmod {m}\)。
数据范围:\(1 \le k < m \le 10^{12}\)。
题解
容易发现,题目给出的同余式子可以转化为如下形式:
移项,简单 BSGS 即可。
留作习题?
APIO2025 T1……
其实是去学习了一下的,但感觉只是意会了,没有理好思路,就浅浅地留作习题叭!
狄利克雷卷积与莫比乌斯反演
可能会有若干蠕动的数学公式向我们大踏步的走来,请谨慎观看。
Q:什么是狄利克雷卷积?
A:一个定义在数论函数间的二元运算。
Q:什么是数论函数?
A:定义域为全体自然数的函数。
狄利克雷卷积与莫比乌斯反演
狄利克雷卷积的定义式为:
如果你有点强迫症,希望后面这坨式子更好看一些,也可以写作:
举例:计算 \(\Big( f*g \Big)(6)\)。
狄利克雷卷积与莫比乌斯反演
在引入一些比较重要的概念之前,我们来看一些比较重要的数论函数。
单位函数:\(\varepsilon(n)=[n=1]\)。
幂函数:\(\operatorname{Id}_k(n)=n^k\)。
特别地,
-
当 \(k=1\) 时,为恒等函数 \(\operatorname{Id}(n)=n\)。
-
当 \(k=0\) 时,为常函数 \(\operatorname{I}(n)=1\)。
狄利克雷卷积与莫比乌斯反演
除数函数:\(\sigma_k(n)=\sum_{d \mid n} d^k\)。
特别地,
-
当 \(k=1\) 时,为约数和函数 \(\sigma(n)=n\)。
-
当 \(k=0\) 时,为约数个数函数 \(\tau(n)=1\)。
欧拉函数:\(\varphi(n)=n\prod\limits_{p \mid n,p \in \mathbb{P}}(1-\frac{1}{p})\)。
本页包括上一页提及的所有函数都是积性函数。
狄利克雷卷积与莫比乌斯反演
狄利克雷卷积这一运算有很多特别优秀的性质,比如:
- 若 \(f,g\) 是积性函数,则 \(f*g\) 也是积性函数;
- \(f*g=g*f\);
- \((f*g)*h=f*(g*h)\);
- \(f*(g+h)=f*g+f*h\)。
篇幅有限,就不给出上述相关性质的证明了。感兴趣的话可以自己推,直接把定义式代入进去即可。
狄利克雷卷积与莫比乌斯反演
接下来将给出一些重要的数论函数的狄利克雷卷积结果。
- \(\operatorname{Id}_k*\operatorname{I}=\sigma(k)\)。
- 推广:\(\Big(f*\operatorname{I}\Big)(n)=\sum\limits_{d \mid n} f(d)\)。
-
\(\varphi*\operatorname{I}=\operatorname{Id}\)。
-
\(\operatorname{I}*\operatorname{I}=\tau\)。
哎,这些东西会经常在莫反里面大放异彩。他们都有一个共同的性质——与 \(\operatorname{I}\) 卷积。
狄利克雷卷积与莫比乌斯反演
单位元相关……
你不需要知道单位元的具体定义。你只需要知道,如果一个函数 \(\omega\) 对于任意的数论函数 \(f\),在狄利克雷卷积运算中,满足 \(f*\omega=f\),则称 \(\omega\) 为狄利克雷卷积的单位元。
结论:狄利克雷卷积这一运算的单位元正是单位函数 \(\varepsilon(n)\)。
这个结论正确性显然。
上式直观地阐释了结论的正确性。
狄利克雷卷积与莫比乌斯反演
狄利克雷逆相关……
定义:如果数论函数 \(f,f^{-1}\) 满足 \(f*f^{-1}=\varepsilon\),则称 \(f^{-1}\) 是 \(f\) 的狄利克雷逆。
然后是一些关于狄利克雷逆的重要的性质或者结论。
- 一个数论函数 \(f(n)\) 存在狄利克雷逆的充要条件是 \(f(1) \neq 0\);
- \(f(n)\) 的狄利克雷逆如果存在,则一定有且仅有一个。
- 积性函数一定有狄利克雷逆,且其相应的狄利克雷逆也是积性函数。
狄利克雷卷积与莫比乌斯反演
长舒一口气,狄利克雷卷积的前置铺垫已经结束,接下来进入莫比乌斯反演。
先来聊莫比乌斯函数 \(\mu(n)\),给出两种定义:
定义一
定义二
狄利克雷卷积与莫比乌斯反演
根据定义一,容易发现如下结论
简单按狄利克雷卷积定义式展开,有:
由上式,我们称 \(g(n)\) 是 \(f(n)\) 的莫比乌斯变换,\(f(n)\) 是 \(g(n)\) 的莫比乌斯反演。
狄利克雷卷积与莫比乌斯反演
你发现莫比乌斯函数是一个积性函数,所以莫比乌斯函数值可以直接线性筛预处理。
可能在应用上各位还有些问题,这边建议结合下面的例题食用。
最常见的应用就是,结合前面狄利克雷卷积的相关公式,起到一个推式子的作用。
例题
\(T\) 组多测,给定正整数 \(a,b,d\),计算:
数据范围:\(1 \le T \le 5 \times 10^4 ,\ 1 \le d \le a,b \le 5\times 10^4\)。
Hint or sol
显然是莫反推式子。
数论分块即可。
留作习题?
建议诸位得空的时候,搜索一套莫反题单,全刷完就好了。
杜教筛
用于在优于线性时间复杂度求解数论函数的前缀和。
形式化地,对于数论函数 \(f(n)\),求 \(\sum_{i=1}^{n}f(i)\)。
考虑构造一个数论函数 \(g\),根据前文狄利克雷卷积的知识,有:
记住这个式子,后面要考。
杜教筛
你发现你构造的这个东西,可以写出一个神秘的递推式,形如:
(云落曾经对着这个式子一直在犯唐……)
综上所述,只要构造出的 \(g\) 性质很优,支持快速计算 \(\sum_{i=1}^{n}(f*g)(i)\) 以及 \(g(i)\) 的前缀和,就可以在优于线性的时间复杂度内解决这个数论函数前缀和的问题。
具体地,前者直接算,后者数论分块。
例题
给定 \(n\),计算:
数据范围:\(1 \le n \le 10^{11}\)。
题解
和前面莫反的例题很类似,枚举约数 \(d\),把 \([\gcd(i,j)=1]\) 的部分套个莫反,调整一下枚举上界……最后你会得到这样一个式子:
令 \(S(n)=\sum_{i=1}^{n} \varphi(i)\),杜教筛板板题。
然后答案变成
这回是数论分块板板题。
杂《》选吃
之所以设计这个部分,主要是云落个人认为,数论相关例题不应当照着算法标签写题。
Round 1
\(T\) 组多测。给定 \(n,m\),求 \([1,n!]\) 中与 \(m!\) 互质的数的数量。
答案对 \(p\) 取模,保证 \(p\) 是质数且 \(p>n\)。
数据范围:\(1 \le T \le 10^4 ,\ 1 \le m \le n \le 10^7\)。
Sol 1
形式化刻画答案,如下:
根据经典结论 \(\gcd(x,y)=\gcd(x+y,y)\),如果存在一个 \(x \in [1,m!]\),使得 \(\gcd(x,m!)=1\),那么 \([km!+1,(k+1)m!]\) 范围内一定会唯一对应一个 \(x+km!\) 满足 \(\gcd(x+km!,m!)=1\)。这保证了上述式子的正确性。
然后把 \(m!\) 唯一分解了,写成 \(\prod {p_i}^{q_i}\) 的形式。
欧拉函数往里一带,\(m!\) 直接约掉,里面的 \(\prod\) 也就是四则运算的事,给分母求一求逆元就齐活了。
Round 2
给定一个序列 \(a\),定义其权值为:
请你重排这个序列,最大化权值。
数据范围:\(1 \le n \le 10^5 ,\ 1 \le a_i \le 5 \times 10^6\)。
温馨提示:时限 \(4s\),可以肆意挥霍。
Sol 2
记 \(f_i\) 表示目前前缀 \(\gcd\) 为 \(i\),前缀 \(\gcd\) 和的最大值。
注意到重排后的序列上一定有一个性质,即对于任意一个前缀的 \(\gcd\),这个前缀以外的数一定都不是这个 \(\gcd\) 的倍数(调整法易证)。
为了方便方程刻画,记 \(cnt_i\) 表示含有因子 \(i\) 的 \(a_i\) 的数量。
容易发现,对于一个 \(i\),你可以枚举它的所有倍数 \(j\) 作为转移来源,而对答案的贡献就一定是那些是 \(i\) 的倍数但不是 \(j\) 的倍数的数,即 \(cnt_i-cnt_j\)。因此,转移方程如下:
时间复杂度 \(O(V \ln V)\),其中 \(V\) 表示值域。
Round 3
\(T\) 组多测。给定四个整数 \(a,b,c,d\),从区间 \([a,b]\) 和 \([c,d]\) 中任选两个整数 \(x\) 和 \(y\),求 \(\gcd(x,y)\) 的最大值是多少。
数据范围:\(1 \le T \le 10^3 ,\ 1 \le a,b,c,d \le 10^9\)。
Sol 3
数论题特有的阴间数据范围,线性筛没什么前途,所以想到枚举这个神秘的 \(\gcd\)。
你发现如果一个 \(\gcd\) 合法,那么在 \([a,b]\) 和 \([c,d]\) 中一定有它的倍数。
判断一个区间 \([l,r]\) 是否存在 \(x\) 的倍数,经典套路之判断下列式子的合法性。
稍微整理一下,得到:
重要的进一步转化——
分别带入 \(a,b,c,d\),有:
根据上面的式子,我们就没有必要线性复杂度枚举 \(x\) 了,套一个简单整除分块
即可,时间复杂度根号量级。
Round 4
\(T\) 组多测。给定 \(n,m\),求序列 \(a_1,a_2,\dots,a_n\) 有多少种和小于等于 \(m\) 的方案,方案数对 \(19491001\) 取模。
数据范围:\(1 \le n,m \le 10^{18}\)。
Round 5
给定 \(n\),计算:
数据范围:\(1 \le n \le 10^6\)。
同时展示了两个题,第一个题还是太简单了。
Sol 4
给诸位投喂一个模板题换换口味。
答案是 \(C_{n+m}^{m} \bmod 19491001\),模数大小区区 \(10^7\),当然可以卢卡斯定理。
Sol 5
重要结论:不妨设 \(a \ge b\),有 \(\gcd(a,b) \le a-b \le a\oplus b\)。
令 \(d=a-b\),枚举 \(d\),枚举 \(d\) 的倍数,每次 \(O(1)\) 判断异或的取等条件,时间复杂度 \(O(n \ln n)\)。
原题有多测,还需预处理答案的差分数组;数据范围 \(10^7\),但是时限 \(5s\)。
Round 6
给定 \(n\),计算:
数据范围:\(1 \le n \le 10^{10}\)。
Sol 6
莫反发力,也有更简单的做法。限于篇幅,这里介绍后者。莫反做法去参考相关题解。
考虑狄利克雷卷积告诉我们的重要结论(在欧拉函数那一部分也出现过了)。
说人话就是——
嗯,记住这个式子。
那么,还是对 \(\gcd(i,j)\) 的部分动手术。
然后就是经典套路,交换求和顺序,把枚举 \(d\) 丢到前面去,有:
还是经典套路,枚举倍数等价于先把数提出来再枚举“倍”,有:
其中记 \(B=\lfloor \frac{n}{d} \rfloor\)。
继续转化这个式子,先合并,再分裂,有:
后面的可以简单整除分块维护,前面的容易想到杜教筛。
问题转化为如何构造一个合适的数论函数 \(g(d)\),使得可以快速计算 \(f*g\)。
为了方便维护,我们肯定不希望 \(f*g\) 的函数内部出现一些神秘的东西,让 \(f*g\) 里只出现变量 \(n\) 应当是上上策。
然后你发现 \(f\) 的后面有个 \(d^2\),尝试构造 \(g\) 把它消掉,比如令 \(g=\operatorname{Id}_2\),因此有:
好了,求 \(f*g\) 等价于求立方和,求 \(g\) 的前缀和等价于求平方和。
剩下的就是代码实现了,依旧是依照题意写代码。
Round 7
定义 \(f(x)\) 为满足 \(ijk=x\) 的三元组 \((i,j,k)\) 个数。给定 \(n\),求 \(\sum_{i=1}^{n}f(i)\)。
数据范围:\(1 \le n \le 10^{10}\)。
一题多解,建议深度思考。
Sol 7
-
朴素做法(难度:黄)
-
数论分块(难度:蓝)
-
莫反 \(+\) 杜教筛(难度:紫)
莫比乌斯反演 \(+\) 杜教筛做法
形式化一下目标答案,有:
然后后面这坨可以改写称枚举 \(i\) 的倍数,形如:
典中典之交换求和号,得:
注意到里面的式子与约数 \(i\) 无关,所以有:
其中 \(d(x)\) 表示 \(x\) 的约数个数。
显然可以数论分块,问题转化为快速求 \(d(x)\) 的前缀和。
根据狄利克雷卷积相关内容,有 \(d * \mu = \operatorname{I}\)。
那么套一层莫反之后,就得到了 \(d(x)\) 前缀和的式子,如下:
嗯?怎么变成莫比乌斯函数的前缀和了?没关系,再来一个杜教筛与数论分块就好了。
时间复杂度 \(O(???)\)。
简单的问题复杂化,复杂的问题抽象化,抽象的问题离谱化,离谱的问题____化?
数论分块做法
还是推式子,这次少推一点。
经典数论分块的形式,问题又双叒叕转化为了求约数个数函数的前缀和。
为了方便表述,记 \(S(n)=\sum_{i=1}^{n} d(i)\)。
难道我们又要莫反杜教筛吗?不,我们还有小清新分治做法。
如果 \(n \le 10^7\),可以直接预处理 \(S(n)\)。
而如果 \(n>10^7\),你发现可以推式子(依据是 \(\operatorname{I} * \operatorname{I}=d\)),有:
然后你大可以对这么个式子数论分块,于是乎就做完了。
朴素做法
啧,考虑对 \((i,j,k)\) 简单分讨(分讨后有序三元组转化为无序三元组)。
-
\(i \neq j \neq k\),对答案的贡献为 \(6\),枚举 \(i,j\) 即可。
-
\(i = j \neq k\),枚举 \(i\) 即可。
-
\(i=j=k\),无需枚举,直接计算贡献。
时间复杂度 \(O(n^{\frac{2}{3}}+n^{\frac{1}{2}}+n^{\frac{0}{1}})\)。
真是,难评。
杂《》选吃的题单
P2155
CF1614D2
P3579
P5160
UVA12716
P3768
P10239