Last updated on
数论基础内容
常见的数学符号
- x∣y :表示 x 整除 y ,即 y%x==0 ,也即 x 是 y 的因数。
- x mod y :表示 x%y,3%2=1
- gcd :最大公约数, gcd(5,10)=5 ,有时直接用 (x,y) 表示
- lcm :最小公倍数, lcm(6,8)=24 ,有时直接用[x,y]表示
- ⊥ :互质, x⊥y 即 gcd(x,y)=1
- a≡b(modm) :同余关系, amodm=bmodm,也可以写成 a+mx=b
- ∑i=1n :求从1到n的和,∑d∣n1 表示求约数个数, ∑d∣nd 表示求约数和
- ⌊yx⌋ :下取整,⌊35⌋=1
- ⌈yx⌉ :上取整, ⌈35⌉=2
- [n=1] :如果方括号内的条件满足则为1,不满足则为0。
- (kn):组合数 Cnk ,计算公式为 (kn)=k!(n−k)!n! (注意两者顺序)
同余的性质
同余关系是等价关系满足性质
- 自反性:a≡a(modm)
- 对称性:b≡a(modm)⟺a≡b(modm)
- 传递性:a≡b(modm),b≡c(modm)⟹a≡c(modm)
若a≡c(modm),b≡d(modm) ,则其满足线性运算
-
a±b≡c±d(modm)
-
a×b≡c×d(modm)
-
若k×a≡k×b(modm),且k,m互质,则a≡b(modm)
若a≡b(modm),k为正整数,则
ak≡bk(modmk)
若d∣a,d∣b ,d|m,则
da≡db(mod dm)
若d∣m,则
a≡b(modd)
一个很常见的恒等式(要求p为一个质数)
(1+x)p≡1+xp(modp)
我们利用二项式来进行简单的证明
(1+x)p=(0p)+(1p)x1+(2p)x2+⋯+(pp)xp
其中(ip)在 0<i<p 时必然是一个整数,且分子的质数 p 不会被任何数约去,故
(1p)≡(2p)≡⋯≡(p−1p)≡0(modp)
该恒等式即得证
快速幂
快速幂板子
int ksm(int a, int b, int m) {
a %= m;
int res = 1;
while (b) {
if (b & 1) res = res * a % m;
a = a * a % m;
b >>= 1;
}
return res;
}
1713=17(1101)2=17(1000)2+(100)2+(1)2=17(1000)2∗17(100)2∗17(00)2∗17(1)2
17=17=17(1)2
17∗17=289=17(10)2
289∗289=83521=17(100)2
83521∗83521=6975757441=17(1000)2
根据以上数据,我们可以得到,成功将13次运算在4次运算内解决
1713=17∗83251∗6975757441
我们将a的幂(即b)二进制进行遍历,如果这一位是1,我们需要乘上对应的 a2i
a = a * a % m 这一步就是在计算 a2i ,而我们需要计算多少个a就取决于b的二进制有多少位,于是这个算法的时间复杂度就是 log 级别
题目链接:
快速幂
矩阵快速幂(拓展内容,可选做)
快速幂求逆元
幺元:也叫单位元,一般用 e 表示,满足ex=x
逆元:一般用inv()表示,一个元素与它的逆元满足a∗inv(a)=e
对于同余关系,其幺元为1,因为1∗x≡x(modm)
我们可以找到根据费马小定理找到a的逆元(即 ax≡1(modm) 的解)
并解同余方程 ax≡b(modm) 的解,等式两边同时乘inv(a),方程变为
inv(a)∗a∗x≡inv(a)∗b(modp)
e∗x≡inv(a)∗b(modp)
x≡inv(a)∗b(modp)
求模运算下的逆元可以根据费马小定理求出inv(a)
首先介绍费马小定理(证明见费马小定理)
ap≡a(modp)
或
ap−1≡1(modp)
其中p为质数
将左边的式子分开写我们能得到
a∗ap−2≡1(modp)
再来看逆元的形式
a∗inv(a)≡1(modp)
两式对比可以得到
inv(a)≡ap−2(modp)
代入 x≡inv(a)∗b 即可得到方程 ax≡b(modm) 的解,这个解可以用快速幂来解决
int inva=ksm(a, p - 2);
练习题
求组合数——Y佬专门造数据提供的题目
GCD LCM
唯一分解定理
N=p1k1p2k2p3k3⋯pnkn
其中p均为质数,任何一个数都能分解成若干个质数的乘积,两个数的gcd即为每个质数阶的min,lcm即为每个质数阶的max
gcd(a,b)=p1min(ka1,kb1)p2min(ka2,kb2)⋯pnmin(kan,kbn)
lcm(a,b)=p1max(ka1,kb1)p2max(ka2,kb2)⋯pnmax(kan,kbn)
根据唯一分解定理可以得到以下性质
(a1,a2,a3⋯an)=(∣a1∣,∣a2∣,∣a3∣⋯∣an∣)
(a,b)=(b,a)
(a,a)=(a,0)=a
(an,bn)=(a,b)n
(a,b)[a,b]=∣ab∣
(a,b)(b,c)(c,d)(a,b,c)2=[a,b][b,c][c,d][a,b,c]2
练习题
分解质因子
蓝桥杯宝石组合
辗转相除法
根据以下两条性质,我们可以得到辗转相除法代码
gcd(a,b)=gcd(b,a%b)=gcd(a%b,b%(a%b)) 或 gcd(bq+r,a)=gcd(a,r)
gcd(a,0)=a
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
在cpp中可以使用 __gcd(a,b) 得到最大公约数
练习题
最大公约数
又是毕业季
质数筛
详见积性函数大杂烩
模板
埃筛
vector<bool> isp(N,true);
vector<int> primes;
void eratosthenes(int n){
isp[0] = isp[1] = false;
for(int i=2;i<=n;i++){
if(isp[i]){
primes.push_back(i);
for(int j=2*i;i<n;j+=i){
isp[j]=false;
}
}
}
}
欧拉筛
vector<bool> isp(N,true);
vector<int> primes;
void get_prime(int n){
isp[0] = isp[1] = false;
for(int i=2;i<=n;i++){
if(isp[i])primes.push_back(i);
for(auto p:primes){
if(p*i>n)break;
isp[p*i]=false;
if(i%p==0){
break;
}
}
}
}
练习题
输出第k小的素数
卢卡斯定理
定义内容
卢卡斯定理(Lucas’ theorem)是一个组合数学中的定理,它描述了模素数 p 的二项式系数。具体来说,若 n 和 k 是非负整数,并且 p 是素数,那么二项式系数 (kn) 模 p 的值可以通过以下公式计算:
(kn)≡i=0∏m(kini)(modp)
其中,ni 和 ki 是 n 和 k 在基数 p 下的数字表示,即:
n=n0+n1p+n2p2+⋯+nmpm
k=k0+k1p+k2p2+⋯+kmpm
且 0≤ni,ki<p。
比赛中常用以下形式
Cab≡C⌊pa⌋⌊pb⌋⋅Ca%pb%p(modp)
证明
根据二项式展开
(1+x)a=(0a)x0+(1a)x1+(2a)x2+(3a)x3+⋯+(na)xa
则我们要求的 (ba) 就是 xb 项所对应的次数,下面我们将 a 进行一下变形
(1+x)a=(1+x)a0+a1∗p=(1+x)a0∗(1+x)a1∗p
其中 a0=a%p,a1=a/p
根据前面证明的式子
(1+x)p≡1+xp(modp)
我们可以得到
(1+x)a≡(1+x)a0∗(1+xp)a1(modp)
将b变为 b0+b1∗p ,则不难看出 xb0 仅能由 (1+x)a0贡献得到,xb1∗p 仅能由 (1+x)a1∗p 贡献得到
那么我们将两项对应系数分别展开,并选择能 b0,b1∗p 的两项相乘,与左式 (1+x)a 展开的 xb 项对比,即可得到
(ba)≡(b0a0)∗(b1a1)≡(b%pa%p)(⌊b/p⌋⌊a/p⌋)(modp)
模板
const int N = 100010;
#define int long long
int a[N];
int p;
int pow(int a,int b,int p){
int ans=1;
while(b){
if(b&1)ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return ans;
}
int C(int n,int m){
if(m>n)return 0;
return ((a[n]*pow(a[m],p-2,p))%p*pow(a[n-m],p-2,p)%p);
}
int Lucas(int n,int m){
if(!m)return 1;
return C(n%p,m%p)*Lucas(n/p,m/p)%p;
}
void solve(){
int n,m;
cin>>n>>m>>p;
a[0]=1;
for(int i=1;i<=p;i++)a[i]=(a[i-1]*i)%p;
cout<<Lucas(n+m,n)<<endl;
}
练习题
卢卡斯定理