质因数分解&约数
我们知道可以对一个数进行质因数分解,即
对一个数进行质因数分解后:
约数个数和:
约数和:
最大公约数与最小公倍数
求最大公约数的方法是经典的欧几里得算法:
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)。