质因数分解&约数
我们知道可以对一个数进行质因数分解,即
对一个数进行质因数分解后:
约数个数和:
约数和:
最大公约数与最小公倍数
求最大公约数的方法是经典的欧几里得算法:
Code:
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
最大公约数和最小公倍数的关系:
扩展欧几里德算法
Code:
void ex_gcd(int a,int b,int &x,int &y)
{
if (b==0) {x=1; y=0; return;}
ex_gcd(b,a%b,x,y);
int t=x; x=y; y=t-a/b*y;
}
利用扩展欧几里德算法可以解不定方程 a∗x+b∗y=n 。
- 首先令 d=gcd(a,b) ,若 d∣n 则有解,否则无解。
- 将
a,b,n
都除以
d
,得到新方程
a0∗x+b0∗y=n0 ,此时 gcd(a0,b0)=1 。 - 利用扩展欧几里德算法求出方程 a0∗x+b0∗y=1 的一组解 x0,y0 ,则 x0∗n0,y0∗n0 是原方程的一组解。
- 根据相关定理,方程
a0∗x+b0∗y=n0
的所有解为
x=x0∗n0+t∗b0,y=y0∗n0−t∗a0,t∈Z
模线性方程 a∗x≡b (mod p) 可以转化为 a∗x+p∗y=b 的形式,也可以用上述方法解决。
快速幂
二分的思想.
Code:
inline int quick_power(int a,int b)
{
int ans=1;
for (int i=b;i;i>>=1,a=a*a%P)
if (i&1) ans=ans*a%P;
return ans;
}
快速乘
二进制的思想,防止直接乘法爆掉.
Code:
int mul(int a,int b)
{
int ans=0;
for (int i=b;i;i>>=1,a=(a<<1)%p)
if (i&1) ans=(ans+a)%p;
return ans;
}
线性筛素数
素数即只有1和自己两个约数的数。
线性筛素数Code:
inline void get_prime()
{
for (int i=2;i<=n;i++)
{
if (!flag[i]) prime[++prime[0]]=i,pos[i]=prime[0];
for (int j=1;j<=prime[0]&&i*prime[j]<=n;j++)
{
flag[i*prime[j]]=1; pos[i*prime[j]]=j;
if (i%prime[j]==0) break;
}
}
}
这个过程的复杂度是 O(n) 的,重点在于
上文中我们知道了可以对一个数进行 质因数分解,
也就是说每个数都存在一个最小质因子 p ,保证复杂度为线性的原因就是每个数只会被它的最小质因子
比如当前 i=4 , i%prime[1]=0(prime[1]=2,prime[2]=3) ,那么此时将 i∗prime[2] 即 8 标记为合数,而
知道了线性的原因,我们也可以很方便的找出每个数的最小质因子。
欧拉函数
线性筛欧拉函数Code:
inline void get_phi()
{
phi[1]=1;
for (int i=2;i<=n;i++)
{
if (!flag[i]) {prime[++prime[0]]=i; phi[i]=i-1;}
for (int j=1;j<=prime[0]&&i*prime[j]<=n;j++)
{
flag[i*prime[j]]=1;
if (i%prime[j]==0) {phi[i*prime[j]]=phi[i]*prime[j]; break;}
else phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
欧拉函数是小于
n
的数中与n**互质**的数的数目,我们用
依旧是先进行质因数分解。
通式:
这个可以用定义+ 容斥原理来证明,此处省略。
特殊: φ(1)=1 。
一些性质:
- 若
n
是质数
p 的 k 次幂,则φ(n)=pk−pk−1=(p−1)∗pk−1 ,因为除了 p 的倍数外,其他数都跟n 互质。 - 积性函数:若 m,n 互质,则 φ(mn)=φ(m)∗φ(n)
- 当
n
为奇数时,
φ(2n)=φ(n) 。 - 当
n
为质数时,
φ(n)=n−1 。 - 当
n
为质数时,且
i%n=0 ,则 φ(i∗n)=φ(i)∗n 。 - 在区间
[0,n)
中与
n
互质的数和为
φ(n)∗n2 。 - ∑d∣nφ(d)=n 。
线性筛欧拉函数就是根据性质 2,4,5 来进行的。
乘法逆元
定义:满足
a∗k≡1 (mod p)
的
k
值就是
乘法逆元的求法:
- 根据定义,我们可以列出不定方程 a∗x+p∗y=1 ,然后用扩展欧几里德算法解决。
- 根据费马小定理,
ap−1≡1 (mod p)
,那么因为
a∗ap−2=ap−1≡1 (mod p)
,所以在
p
是质数时,
a 关于 p 的逆元为ap−2 。 - 递推求逆元,复杂度为 O(n) ,附代码,证明略
inv[1]=1;
for (int i=2;i<MAXN;i++) inv[i]=(p-p/i)*inv[p%i]%p;
以上为乘法逆元常用的 3 种求法。
高斯消元
高斯消元就是不断地消元然后回代,可用来解线性方程组,复杂度为
Code:
void gauss()
{
int y;
double t;
for (int i=1;i<=n;i++)
{
for (y=i;y<=n;y++)
if (fabs(a[y][i])>eps) break;
if (y>n) continue;
if (y!=i)
for (int j=1;j<=n+1;j++) swap(a[i][j],a[y][j]);
t=a[i][i];
for (int j=1;j<=n+1;j++) a[i][j]/=t;
for (int j=1;j<=n;j++)
if (j!=i)
{
t=a[j][i];
for (int k=1;k<=n+1;k++)
a[j][k]-=t*a[i][k];
}
}
}
高斯消元还可以用来解异或方程组,然后引入一个概念叫做自由元:在消元后若
fi,i=0
,证明
i
是一个自由元,即
Code:
inline void gauss()
{
int y;
for (int i=1;i<=n;i++)
{
for (y=i;y<=n;y++)
if (a[y][i]) break;
if (y>n) continue;
if (i!=y)
for (int j=1;j<=n+1;j++) swap(a[i][j],a[y][j]);
for (int j=1;j<=n;j++)
if (j!=i&&a[j][i])
for (int k=1;k<=n+1;k++) a[j][k]^=a[i][k];
}
}
void dfs(int x)
{
if (tot>=mn) return;
if (!x)
{
mn=min(mn,tot);
return;
}
if (a[x][x])
{
int t=a[x][n+1];
for (int i=x+1;i<=n;i++)
if (a[x][i]) t^=ans[i];
ans[x]=t;
if (t) tot++;
dfs(x-1);
if (t) tot--;
}
else
{
ans[x]=0; dfs(x-1);
ans[x]=1; tot++; dfs(x-1); tot--;
}
}
Lucas定理
Lucas
定理是用来解决大组合数取模的。
即求
Cmn mod p
,其中
p
为质数。
莫比乌斯反演
线性筛莫比乌斯函数Code:
inline void prepare()
{
mobius[1]=1;
for (int i=2;i<MAXN;i++)
{
if (!flag[i]) prime[++prime[0]]=i,mobius[i]=-1;
for (int j=1;j<=prime[0]&&i*prime[j]<MAXN;j++)
{
flag[i*prime[j]]=1;
if (i%prime[j]==0)
{
mobius[i*prime[j]]=0;
break;
}
mobius[i*prime[j]]=-mobius[i];
}
}
}
参考资料:WC2016第二课堂宋新波讲稿
我们定义两个函数
f(n)
和
g(n)
,并且满足
f(n)=∑d∣ng(d)
,根据定义:
f(1)=g(1)
f(2)=g(1)+g(2)
f(3)=g(1)+g(3)
f(4)=g(1)+g(2)+g(4)
f(5)=g(1)+g(5)
f(6)=g(1)+g(2)+g(3)+g(6)
f(7)=g(7)
f(8)=g(1)+g(2)+g(4)+g(8)
于是我们可以得到:
g(1)=f(1)
g(2)=f(2)−f(1)
g(3)=f(3)−f(1)
g(4)=f(4)−f(2)
g(5)=f(5)−f(1)
g(6)=f(6)−f(3)−f(2)+f(1)
g(7)=f(7)−f(1)
g(8)=f(8)−f(4)
我们发现了什么?
g(n)=∑d∣nf(d)×?
而
?
部分与
我们定义一个新的函数,记为
μ(i)
则
g(n)=∑d∣nf(d)×μ(nd)
或者通过换元可以写成
g(n)=∑d∣nf(nd)×μ(d)
我们得到了公式:
f(n)=∑d∣ng(d)=>g(n)=∑d∣nf(nd)×μ(d)
莫比乌斯函数的定义
μ(d)
为莫比乌斯函数,定义如下:
①若
d=1
,则
μ(d)=1
②若
d=P1×P2×...×Pn
,则
μ(d)=(−1)k
③其他情况
μ(d)=0
莫比乌斯函数的性质
①若
n=1
,则
∑d∣nμ(d)=1
,否则
∑d∣nμ(d)=0
.
可以用二项式定理来证明。
②莫比乌斯函数是积性函数
莫比乌斯反演的证明
证明:
f(n)=∑d∣ng(d)=>g(n)=∑d∣nf(nd)×μ(d)
g(n)=∑d∣nf(nd)∗μ(d)
=∑d∣nμ(d)∑i∣ndg(i)
=∑i∣ng(i)∑d∣niμ(d)
①当
i=n
时,
∑d∣niμ(d)=1
,
g(i)∑d∣niμ(d)=g(n)
②当
i
取其他值时,
综上,
g(n)=∑d∣nf(nd)μ(d)=g(n)
莫比乌斯反演的变形
f(i)=∑i∣d,d≤ng(d)=>g(i)=∑i∣d,d≤nf(d)μ(di)
其他写法:
f(i)=∑⌊ni⌋d=1g(d∗i)=>g(i)=∑⌊ni⌋d=1f(d∗i)μ(d)
证明与莫比乌斯反演的证明类似,在此不赘述。
莫比乌斯反演的性质
f(n)=∑d∣ng(d)
,则“
g(n)
是积性函数”的充分必要条件是“
f(n)
是积性函数”。
常用技巧
变量替换,内层外移。
gcd(i,j)=1
等价于
∑d∣gcd(i,j)μ(d)
。