数论基础
数论基础
余数
取模运算
整除分块
参考博客 然而我认为这篇的时间复杂度分析得不太对。
求 $\sum_{i=1}^{n} \lfloor \frac{n}{i} \rfloor $ 这种东西以及其他复杂很多的东西,可以 \(O(\sqrt{n})\) 求解。
最简单地,求 $\sum_{i=1}^{n} \lfloor \frac{n}{i} \rfloor $。
时间复杂度证明
注意到 \(\lfloor \frac{n}{i} \rfloor\) 的取值不超过 \(2\sqrt{n}\) 种。证明如下:
- \(i\le \sqrt{n}\),因为 \(i\) 只有 \(\sqrt{n}\) 种,所以 \(\lfloor \frac{n}{i} \rfloor\) 的取值也只有 \(\sqrt{n}\) 种。
- \(i> \sqrt{n}\),此时 \(\lfloor \frac{n}{i} \rfloor < \sqrt{n}\),显然取值不超过 \(\sqrt{n}\)。
因此总时间复杂度为 \(O(\sqrt{n})\)。
大体思路和代码
枚举 \(l\),设 \(v=\lfloor \frac{n}{l} \rfloor\),我们要找 \(v=\lfloor \frac{n}{r} \rfloor\) 的最大的 \(r\)。
因此在这个例子中,\(r\) 取 \(\frac{n}{v}\),下一块的 \(l\) 就取 \(r+1\)。
for(int l=1,r=1,v=n/l;l<=n;l=r+1,v=n/l){
r=n/v;
ans+=v*(r-l+1);
}
经验
P1403 [AHOI2005] 约数研究 一道小黄题,和例子一模一样,其实它的数据范围可以不用整除分块的。
P2424 约数和 很板子。
P2261 [CQOI2007] 余数求和 把 \(k\bmod i\) 转化成 \(k-\lfloor \frac{k}{i} \rfloor i\),然后看起来非常板子。但是由于 \(i\le n\) 而本题求 \(\lfloor \frac{k}{i} \rfloor\),\(n,k\) 可能不等,需要注意边界细节。
GZOI2024 Day2 T2【乒乓球】 很复杂的整除分块。
约数
\(a|b\) 表示 \(a\) 能整除 \(b\),即 \(a\) 是 \(b\) 的因子。
约数个数大约 \(O(n^\frac{1}{3})\) 级别。
最大公约数
——辗转相除法求 gcd
欧几里得算法: \(\gcd(a,b)=\gcd(b,a\bmod b)\) 。
时间复杂度 \(O(\log n)\)(我不会证明 qwq)。
Code
一行搞定我不是故意压行的。
int gcd(int a,int b){return b?gcd(b,a%b):a;}
O(1) 求 gcd
参考 O(1)gcd 学习笔记。
设 \(T=\lfloor\sqrt{V}\rfloor\)。
对于一个数 \(1\le x\le V\),一定可以拆分成三个数 \(a,b,c\) 相乘。每个数 \(y\) 满足:
- 若 \(y> T\) 则 \(y\) 是质数。
- 否则 \(y\le T\),\(y\) 可以是合数。
因为 \(x\) 可能有至多一个质因子 \(p> T\),如果有,则把 \(x\) 分成 \(p\) 和 \(q\),\(q\) 一定是一个 \(\le T\) 的数,否则 \(pq\) 就 \(\ge (T+1)^2\) 了。那么把 \(q\) 拆成两个数也一定都是 $\le T $ 的。如果没有,假设存在一个合数 \(>T\),那么另外两个数的乘积一定 \(\le T\),否则他们三乘起来就 \(\ge (T+1)^2\) 了。这时候我们把两个小的数乘起来变成一个,然后把大的合数拆开就好了。emm,感性理解一下吧。
不是,我为什么要证明这个东西啊,学 OI 还纠结什么证明?
好的,接下来我们不再证明这些显然的东西了。
O(n) 预处理
线性筛筛出每个数的最小质因数 \(p\),然后这个数的分解方式复制 \(x/p\) 的分解方式,然后从 \(a,b,c\) 依次判断能否乘上 \(p\) 之后仍然合法,合法就乘上好了。
线性同余方程
给定 \(a,b,n\),求 \(x\) 在 \([0,n-1]\) 的整数解。
当 \(a,n\) 互素时,可以逆元求解。
若 \(a,n\) 不互素,此时不一定有解。当且仅当 \(\gcd (a,n) | b\) 的时候有解且恰有 \(\gcd(a,n)\) 个解,可以感性理解。使用逆元或者扩展欧几里得算法求解。
逆元求解
设 \(g=\gcd(a,n)\)。
方程左右及模数同除 \(g\)。
令 \(a'=\frac{a}{g},b'=\frac{b}{g},n'=\frac{n}{g}\),
有 \(a' x' \equiv b' (\bmod n')\)。
可以发现 \(x'\) 也是原方程的一个解。
原方程有 \(g\) 个解。通解为 \(x_i = x'+in'(i \in [0,g-1])\)。
显然这样的解是新方程的解,又因为这样的解 \(\le n-1\),因此这样的解也是原方程的解。
扩展欧几里得算法
同余方程
可以转化为
当且仅当 \(\gcd(a,b)| c\) 的时候有且有 \(\gcd(a,b)\) 个解。
假设 \(gcd(a,b) | c\),设 \(g=gcd(a,b)\)。
方程
的解集和原方程相等。
上面的方程写作
我们先求方程 \(a' x + b' y = \gcd (a', b')\) 的解。
当 \(b'=0\) 的时候,显然有 \(\gcd=a',x=1,y=0\)。
当 \(b > 0\) 的时候,参考辗转相除法的过程。求出方程 \(b' x' + (a' \bmod b') y' = \gcd\) 的解。有
由此得出
素数和合数
一个数有且仅有 \(1\) 和它本身两个因子,这个数是素数,因此 \(1\) 不是素数。
线性筛法
每个数只会被最小的质因子筛到。
复杂度 \(O(n)\) 。
Code
#include<bits/stdc++.h>
#define ll long long
#define pf printf
#define sf scanf
using namespace std;
const int N=1e6+7,M=1e7;
int can[N];
int p[M];
void primes(int n){
for(int i=2;i<=n;i++){
if(!p[i]){
p[i]=i;
can[++can[0]]=i;
}
for(int j=1;j<=can[0];j++){
if(can[j]>p[i]||(ll)can[j]*i>n) break;
p[can[j]*i]=can[j];
}
}
}
int main(){
int n=M;
primes(n);
pf("%d\n",can[0]);
}
乘法逆元
则 \(x\) 是 \(a\) 的乘法逆元。
若 \(a,p\) 不互素,则不存在乘法逆元。
线性求逆元
求连续逆元
结论、证明见 OIWiki。这里搬一张结论。
附上可爱代码:
inv[1]=1;
rep(i,2,n) inv[i]=1ll*(p-p/i)*inv[p%i]%p;
求任意 n 个数的逆元
设 \(s_n\) 表示前 \(n\) 个数的积(取模意义下),先求出 \(s_n^{-1}\),然后倒序一次求出 \(s_i^{-1}\),最后 \(inv_i \gets s_i^{-1} \times s_{i-1}\)。
s[0]=1;
rep(i,1,n) s[i]=1ll*s[i-1]*a[i]%p;
sinv[n]=ksm(s[n],p-2);
per(i,n-1,0) sinv[i]=1ll*sinv[i+1]*a[i+1]%p;
rep(i,1,n) inv[i]=1ll*sinv[i]*s[i-1]%p;
本文来自博客园,作者:liyixin,转载请注明原文链接:https://www.cnblogs.com/liyixin0514/p/18359548