前言
本文总结了一些与 OI 有关的简单数论内容。 由于作者水平有限,部分结论的证明过程省略。
一. 公约数/扩展欧几里得算法
这里将正整数
二. 中国剩余定理
有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?
上面的问题出自《孙子算经》。用现代数学的角度看这个问题,可以归纳为求解以下形式的同余方程组:
对于这个方程组,我们尝试构造这样一组解:
t_i\equiv 1(\mod m_i) t_i\equiv 0(\mod m_j),j\neq i 令M=\prod_{i=1}^k m_i ,即m_1\cdots m_k 的最小公倍数。那么t_i 取方程\frac M{M_i} t_i\equiv 1(\mod m_i) 的最小非负整数解即可满足上述关系。t_i 可以用扩展欧几里得算法求出。将其代入前面的式子,可以得到方程的一组解x ,而通解就是x+iM(i\in\mathbb{Z}) . 特别的,方程的最小整数解为(x\mod M+M))\mod M .
扩展中国剩余定理
此定理适用于
三. Lucas 定理
Lucas 定理主要用于求组合数对给定质数取模的结果,即
扩展 Lucas
此定理适用于
四. 原根
定义
设
m 是正整数,a 是整数,若a 模m 的阶等于\varphi(m) ,则a 为模m 的一个原根。 ——百度百科
数论阶
若
由以上定义可知,不等式等号成立时,
- 模
m 有原根的充要条件是m=1,2,4,p,2p,p^n ,其中p 是奇素数,n 是任意正整数 - 若模一个数
m 有原根,则他有\varphi(\varphi(m)) 个原根
求 m 的任意一个原根
一般来说,一个数最小的原根会比较小,大约是
代码
int get_pr(int n)
{
static int f[MAXN];
int t=n-1, k=0;
for (int i=2; i*i<n; i++)
if (t%i==0)
{
f[++k]=i;
while (t%i==0) t/=i;
}
for (int i=2; i<n; i++)
{
bool flag=1;
for (int j=1; j<=k; j++)
if (qpow(i, (n-1)/f[j])==1)
{
flag=0;
break;
}
if (flag) return i;
}
}
五. BSGS 算法
求以下同余方程的正整数解:
扩展 BSGS
适用于
六. 整除分块
与其说整除分块是一种算法,不如说它是一个技巧。有时我们需要计算这样的式子:
// s[i] 为函数 f(i) 的前缀和
int ans=0;
for (int i=1, j; i<=n; i=j+1)
{
j=n/(n/i);
ans+=(s[j]-s[i-1])*(n/i);
}
printf("%d\n", ans);
七. 莫比乌斯反演
莫比乌斯函数
定义莫比乌斯函数
性质
- 性质一:对于任意一对互质的正整数
p,q ,\mu(pq)=\mu(p)\mu(q) 。所以 莫比乌斯函数是积性函数 。这一性质说明莫比乌斯函数可以被线性筛。
证明: 根据定义,可知若
p,q 中一个包含幂次大于平方的质因子,则它的莫比乌斯函数值为 0 ,那么这两个函数值的乘积也为 0 。否则,因为p,q 互质,所以它们没有相同的质因子。设p,q 的质因子数分别为f(p),f(q) ,则f(pq)=f(p)+f(q) 因为莫比乌斯函数的取值由质因子数的奇偶性决定,容易推出\mu(pq)=\mu(p)\mu(q) 注意,对于不互质的正整数对,由于存在相同的质因子,此命题不成立。所以莫比乌斯函数是积性函数,但不是完全积性函数。
- 性质二:对于任意正整数
n ,\sum_{d|n}\mu(d)=[n=1] 。(这里的[n=1] 表示当且仅当括号内条件成立时值为1 ,否则为0 。下文同。)
证明: 根据定义,当
n=1 时命题显然成立。 当n>1 时, 将n 按上文形式分解质因数。当a_i>1 时函数值为0 ,对整个式子的值没有贡献,可以不用考虑。我们只统计有多少个质因子的指数为1 。那么上述式子可以化为:\sum_{i=0}^k C_k^i*(-1)^i 由二项式定理得:\sum_{i=0}^k\begin{pmatrix}k\\i\\\end{pmatrix}(-1)^i1^{k-i}=[(-1)+1]^k=0
- 性质三:对于任意正整数
n ,\sum_{d|n}\frac{\mu(d)}d=\frac{\varphi(n)}n
这条性质用到的地方不多,因此证明暂时省略。
狄利克雷卷积
狄利克雷卷积是一种数论函数卷积。若数论函数
一些基本的完全积性函数
为了下文展开方便,下面给出一些完全积性函数的记号,这些函数都满足对于任意正整数
- 单位元函数
\varepsilon(n)=[n=1] - 常函数
I(n)=1 - 恒等函数
id(n)=n
容易看出,上文中莫比乌斯函数的性质二可记作
莫比乌斯反演定理
证明: 原式可以表示为狄利克雷卷积的形式,即
f=g*I . 在等式两边同时卷上\mu ,得f*\mu=g*I*\mu 由\mu*I=\varepsilon ,得f*\mu=g 展开即结果式。
例题
Luogu3455&BZOJ1101 【POI2007 ZAP-Queries】
题意
题解
不妨设
八. 杜教筛
杜教筛是一种求积性函数前缀和的低于线性的筛法。我们有时要求
例题
Luogu3768 【简单的数学题】
题意
给定
题解
先根据莫比乌斯反演的老套路,设
代码
#include <cstdio>
#include <cmath>
#include <cstring>
#include <tr1/unordered_map>
using namespace std;
using namespace std;
typedef long long ll;
const int MAXN=5E6;
int p, lim, inv2, inv6; ll n;
int prim[MAXN], phi[MAXN];
int sum[MAXN];
bool book[MAXN];
tr1::unordered_map<ll, int> hash;
void exgcd(int a, int b, int& x, int& y)
{
if (b==0) x=1, y=0;
else exgcd(b, a%b, y, x), y-=a/b*x;
}
inline int pre(ll n)
{
n=n%p;
return n*(n+1)%p*inv2%p;
}
inline int square(ll n)
{
n=n%p;
return n*(n+1)%p*(2*n+1)%p*inv6%p;
}
inline int cube(ll n)
{
return 1ll*pre(n)*pre(n)%p;
}
void sieve()
{
memset(book, 0, sizeof book);
phi[1]=1;
for (int i=2, cp=0; i<=lim; i++)
{
if (!book[i]) prim[++cp]=i, phi[i]=i-1;
for (int j=1; j<=cp&&i*prim[j]<=lim; j++)
{
book[i*prim[j]]=1;
if (i%prim[j]==0)
{
phi[i*prim[j]]=phi[i]*prim[j];
break;
}
phi[i*prim[j]]=phi[i]*(prim[j]-1);
}
}
for (int i=1; i<=lim; i++) sum[i]=(sum[i-1]+1ll*i*i%p*phi[i]%p)%p;
}
int djs(ll n)
{
if (n<=lim) return sum[n];
if (hash.count(n)) return hash[n];
int res=cube(n);
for (ll d=2, k; d<=n; d=k+1)
{
k=n/(n/d);
res=(res-1ll*(square(k)-square(d-1))*djs(n/d)%p+p)%p;
}
return hash[n]=res;
}
int main()
{
// freopen("P3768.in", "r", stdin);
// freopen("P3768.out", "w", stdout);
scanf("%d%lld", &p, &n);
int t;
exgcd(2, p, inv2, t);
exgcd(6, p, inv6, t);
inv2=(inv2+p)%p; inv6=(inv6+p)%p;
lim=pow(n, 2.0/3);
sieve();
int ans=0;
for (ll i=1, j; i<=n; i=j+1)
{
j=n/(n/i);
int s=pre(n/i);
ans=(ans+1ll*s*s%p*(djs(j)-djs(i-1))%p+p)%p;
}
printf("%d\n", ans);
return 0;
}
九. Powerful Number 优化积性函数前缀和
这种求积性函数前缀和的方法和杜教筛十分相似。先以一道题为例:
已知
f(x) 为积性函数,满足f(p^q)=p^k ,其中p 为质数,k 为定值。求f(x) 的前n 项和。
先定义 Powerful Number 为每个质因子的幂次都
证明: 由于每个质因子间是独立的,易证所有 Powerful Number 都可以表示成
a^2b^3 的形式。考虑枚举a 则n 以内这种数的数量为O\left(\sum_{a=1}^{\sqrt n}\left(\frac n{a^2}\right)^{\frac 1 3}\right) =O\left(\int_1^{\sqrt n}\left(\frac n{x^2}\right)^{\frac 1 3}dx\right) =O(\sqrt n) 考虑构造数论函数g,h ,使f=g*h ,且g(p)=f(p) . 可以令g(x)=x^k ,这样当p 为质数时,有f(p)=g(1)h(p)+g(p)h(1) 由于g(1)=h(1)=1 ,可以得出h(p)=0 . 又因为h 是积性函数,所以仅当x 为 Powerful Number 时,h(x) 才不为 0. 考虑求解答案。答案为\sum_{i=1}^n f(i)=\sum_{ij\leq n}g(i)h(j) =\sum_{i=1}^nh(i)\sum_{j=1}^{\lfloor\frac n i\rfloor}g(j) 后面的g 的前缀和可以用插值等求自然数幂和的方法快速求出。现在唯一的问题就是求所有 Powerful Numberx 的h(x) . 由于f,g 都是积性函数,所以h 也是积性函数。因此我们考虑求h(p^q) . 由f=g*h ,有以下等式:f(p^q)=\sum_{i=0}^q g(p^i)h(p^{q-i}) p^k=\sum_{i=0}^q p^{ik}h(p^{q-i}) 令h(p^q)=p^k-p^{2k} ,等式成立。这样我们就可以在搜索 Powerful Number 时顺便把它们的h(x) 的值也求出来了。
十. min-25 筛
以下内容部分引用自租酥雨的博客,并加入了一些自己的理解。
min-25 筛与杜教筛相似,也是一种求积性函数前缀和的方法。一般来说,它的适用范围更加广泛,设
f(p) 可以用简单多项式表示f(p^k) 可以快速计算
预处理
设
考虑
g(n,j) 的转移,分两种情况:
P_j^2>n 。此时运行的第j次已经不会再筛掉任何数了(因为第j 次运行中筛掉的最小的数是P_j^2 ,所以此时g(n,j)=g(n,j−1) .P_j^2\leq n 。这时候我们就要考虑哪些数被筛掉了。被筛掉的数一定含有质因子P_j ,且除掉P_j 后最小的质因子会大于等于P_j 。考虑减去f(P_j)\cdot g(\lfloor\frac n{P_j}\rfloor,j−1) ,但在g(\lfloor\frac n{P_j}\rfloor,j−1) 中多减去了\sum_{i=1}^{j-1}f(P_i) 这些最小质因子小于P_j 的函数值,所以再把它们加上就好了。 所以总结起来就是:g(n,j)=\left\{\begin{matrix}g(n,j-1) & P_j^2>n\\g(n,j-1)-f(P_j)\left[g(\lfloor\frac n{P_j}\rfloor,j-1)-\sum_{i=1}^{j-1}f(P_i)\right]&P_j^2\leq n\end{matrix}\right.
观察 DP 方程,发现转移中需要用到的第一维状态就是
复杂度证明: 考虑对于每个
x=\lfloor\frac n i\rfloor ,它只会在枚举P_j\leq\sqrt n 时产生贡献。由素数定理,\sqrt n 内的素数有O\left(\frac{\sqrt n}{\log\sqrt n}\right) 个。因此,时间复杂度可估计为\sum_{i=1}^{\sqrt n}O\left(\frac{\sqrt i}{\log\sqrt i}\right)+\sum_{i=1}^{\sqrt n}O\left(\frac{\sqrt \frac n i}{\log\sqrt\frac n i}\right) =O\left(\int_1^{\sqrt n}\frac{\sqrt \frac n x \mathrm{d}x}{\log\sqrt\frac n x}\right) =O\left(\frac{n^{\frac 3 4}}{\log n}\right)
求解
我们设
S(n,j)=\sum_{i=1}^n[lpf(i)\geq P_j]f(i) ,也就是所有满足最小质因子大于等于P_j 的f 值之和。 那么最终的答案就是S(n,1)+f(1) . 鉴于质数的答案我们已经算出来了,是g(n,|P|)-\sum_{i=1}^{j-1}f(P_i) 。(因为要保证最小质因子大于等于Pj所以要把小于它的质数减掉) 考虑合数。我们枚举这个合数的最小质因子及其出现次数,然后直接乘即可。S(n,j)=g(n,|P|)-\sum_{i=1}^{j-1}f(P_i)+\sum_{k=j}^{p_k^2\leq n}\sum_{e=1}^{p_k^{e+1}\leq n}f(p_k^e)\cdot S(\left\lfloor\frac{n}{p_k^e}\right\rfloor,k+1)+f(p_k^{e+1})
解释一下这个式子,设有一合数为
例题
LOJ6053 【简单的函数】
题意
定义积性函数
题解
要应用 min-25 筛,首先应把
代码
#include <cstdio>
#include <cmath>
#include <cstring>
typedef long long ll;
const int MAXN=110000;
const int MAXM=2*MAXN;
const int MOD=1E9+7;
ll n; int m, sq;
int cp, pri[MAXN], sp[MAXM];
bool book[MAXN];
ll w[MAXM];
int id1[MAXM], id2[MAXM];
int g[MAXM], h[MAXM];
inline int id(ll i)
{
return i<=sq?id1[i]:id2[n/i];
}
void get_prime(int lim)
{
memset(book, 0, sizeof book);
cp=0;
for (int i=2; i<=lim; i++)
{
if (!book[i]) pri[++cp]=i, sp[cp]=(sp[cp-1]+i)%MOD;
for (int j=1; j<=cp&&i*pri[j]<=lim; j++)
{
book[i*pri[j]]=1;
if (i%pri[j]==0) break;
}
}
}
void dp()
{
for (ll i=1, j; i<=n; i=j+1)
{
j=n/(n/i); w[++m]=n/i;
if (w[m]<=sq) id1[w[m]]=m;
else id2[n/w[m]]=m;
g[m]=((w[m]+2)%MOD)*((w[m]-1)%MOD)%MOD;
if (g[m]&1) g[m]+=MOD; g[m]/=2;
h[m]=(w[m]-1)%MOD;
}
for (int j=1; j<=cp; j++)
for (int i=1; i<=m&&1ll*pri[j]*pri[j]<=w[i]; i++)
{
g[i]=((g[i]-1ll*pri[j]*(g[id(w[i]/pri[j])]-sp[j-1]))%MOD+MOD)%MOD;
h[i]=(h[i]-(h[id(w[i]/pri[j])]-(j-1))+MOD)%MOD;
}
}
int calc(ll i, int j)
{
if (i<pri[j]) return 0;
int res=((g[id(i)]-h[id(i)])-(sp[j-1]-(j-1))+MOD)%MOD;
for (int k=j; k<=cp&&1ll*pri[k]*pri[k]<=i; k++)
{
ll p; int e;
for (p=pri[k], e=1; p*pri[k]<=i; p*=pri[k], e++)
res=(res+1ll*(pri[k]^e)*calc(i/p, k+1)+(pri[k]^e+1))%MOD;
}
return res;
}
int main()
{
// freopen("loj6053.in", "r", stdin);
// freopen("loj6053.out", "w", stdout);
scanf("%lld", &n);
sq=sqrt(n);
get_prime(sq);
dp();
printf("%d\n", n==1?1:(calc(n, 1)+3)%MOD);
}