数论知识总结

介绍

在这里插入图片描述

1.素数

定义:对于一个正整数,如果它有且仅有 1 1 1 和它自己两个约数,那么我们称这个数为素数。如果有两个以上的约数,那么我们称这个数为合数。

唯一因子分解定理(质因数分解):合数能被唯一的分解为质数的乘积形式:

a = p 1 k 1 p 2 k 2 . . . p r k r , p 1 < p 2 < . . . < p r a=p_1^{k_1}p_2^{k_2}...p_r^{k_r},p_1<p_2<...<p_r a=p1k1p2k2...prkrp1<p2<...<pr

如何求素数

P3383 【模板】线性筛素数

  1. 暴力枚举: O ( n ) O(\sqrt n) O(n )
  2. 筛法求素数:用每个素数去筛掉它的倍数,时间 O ( n l o g n ) O(nlogn) O(nlogn)
  3. 线性筛素数:在筛法的基础上 我们让每一个合数只能被他自己最小的素数筛到。
    直接看代码:
for(int i = 2;i <= n;i++)
{
	if(!isp[i])p[++cnt] = i;
	for(int j = 1;j <= cnt&&i*p[j] <= n;j++)
	{
		isp[i*p[j]] = true;
		if(i%p[j]==0) break;
	}
}

2.gcd相关

定义: gcd ⁡ ( a , b ) \gcd(a,b) gcd(a,b) 表示 a a a b b b 的最大公约数, lcm ⁡ ( a , b ) \operatorname{lcm}(a,b) lcm(a,b) 表示 a a a b b b 的最小公倍数。

求法

知道这两个公式就行了: gcd ⁡ ( a , b ) = g c d ( a − b , b ) \gcd(a,b)=gcd(a-b,b) gcd(a,b)=gcd(ab,b) lcm ⁡ ( a , b ) = a b gcd ⁡ ( a , b ) \operatorname{lcm}(a,b)=\frac{ab}{\gcd(a,b)} lcm(a,b)=gcd(a,b)ab

代码:

int gcd(int x,int y){return y?gcd(y,x%y):x;}
int lcm(int x,int y){return x/gcd(x,y)*y;}
裴蜀定理

P4549 【模板】裴蜀定理
裴蜀定理:设 d = gcd ⁡ ( a , b ) d=\gcd(a,b) d=gcd(a,b),则d为 { a x + b y } \{ax+by\} {ax+by} x , y ∈ Z x,y\in Z x,yZ)中的最小正数( d d d 的倍数均在集合中且集合中的数都是 d d d 的倍数)
一个重要的推论是: a x + b y = 1 ax+by=1 ax+by=1 有解等价于 a a a b b b 互质。

扩展欧几里得

欧几里得算法只能告诉我们 a x + b y = m ax+by=m ax+by=m 这个方程有没有解( gcd ⁡ ( a , b ) ∣ m \gcd(a,b)\mid m gcd(a,b)m 成不成立),而不能说明解是多少,使用扩展欧几里得算法可以解决这个问题。
a x + b y = d ax+by=d ax+by=d
b ′ x + ( a % b ) y ′ = d b'x+(a\%b)y'=d bx+(a%b)y=d
欧几里得算法是一个递归的过程,那我们也用递归来求解 x x x y y y,现在已知 x ’ x’ x y ’ y’ y,求 x x x y y y
变个形: a % b = a − ⌊ a b ⌋ × b a\%b=a-\lfloor\frac{a}{b}\rfloor\times b a%b=aba×b
然后把含 a a a 的和含 b b b 的分别凑一块: a y ′ + b ( x ′ − ⌊ a b ⌋ × y ′ ) = d ) ay'+b(x'-\lfloor\frac{a}{b}\rfloor\times y')=d) ay+b(xba×y)=d) 就是递推关系了。

代码:

void exgcd(ll a,ll b,ll &x,ll &y)
{
	if(!b){x = 1;y = 0;return;}
	exgcd(b,a%b,x,y);ll t = x;
	x = y;y = t-a/b*y;
}
逆元

对于一个数 x x x,它在模 p p p 意义下的逆元 a a a,满足 a x ≡ 1 ( m o d p ) ax\equiv 1\pmod p ax1(modp)
如何求逆元?

  1. 扩展欧几里得,这式子不是和 a x + b y = m ax+by=m ax+by=m 长得很像吗?直接做就完了,时间复杂度: O ( l o g max ⁡ ( a , b ) ) O(log_{\max(a,b)}) O(logmax(a,b))
  2. 费马小定理:若 p p p 为素数,则 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv1\pmod p ap11(modp),所以 a p − 2 a^{p-2} ap2 就是 a a a 的逆元,用快速幂就行了。
  3. 线性求逆元:
    p p p 写成 k × i + r k\times i+r k×i+r 的形式,其中 0 < r < i 0<r<i 0<r<i(即带余除法)。
    k × i + r ≡ 0 ( m o d p ) k\times i+r\equiv 0\pmod p k×i+r0(modp)
    两边同时除以 r × i r\times i r×i 得: k × r − 1 + i − 1 ≡ 0 ( m o d p ) k\times r^{-1}+i^{-1}\equiv 0\pmod p k×r1+i10(modp)
    所以 i − 1 ≡ − k × r − 1 ( m o d p ) i^{-1}\equiv-k\times r^{-1}\pmod p i1k×r1(modp)
    代码就是:
inv[0] = inv[1] = 1;
for(int i = 2;i <= n;i++)inv[i] = inv[mod%i]*(mod-mod/i)%mod;

P3811 【模板】乘法逆元
P2613 【模板】有理数取余

中国剩余定理(CRT)

P1495 【模板】中国剩余定理(CRT)/ 曹冲养猪
在这里插入图片描述
和拉格朗日插值有点像,只需要构造出一个 x x x 就行了。
M = ∏ i = 1 k m i M=\prod_{i=1}^km_i M=i=1kmi M i = M m i M_i=\frac M{m_i} Mi=miM t i t_i ti M i M_i Mi 的逆元,则 x = ∑ i = 1 n a i M i t i x=\sum_{i=1}^na_iM_it_i x=i=1naiMiti,那么最小解就是 x % M x\%M x%M
证明很简单,你把每个式子带进去算一下就行了。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
int n,a[11],b[11];
ull sum=1,t[11],ans; 
int main()
{
	cin>>n;
	for(int i=1; i<=n; i++) {
		cin>>a[i]>>b[i];
		sum*=a[i];
	} 
	for(int i=1; i<=n; i++) t[i]=sum/a[i];
	for(int i=1; i<=n; i++) 
		for(ull j=t[i]; j<=0x7f7f7f7f7f7f; j+=t[i]) 
		    if(j%a[i]==1) {ans+=j*b[i]%sum;break;}
	cout<<ans%sum;
	return 0;
}
扩展中国剩余定理(exCRT)

P4777 【模板】扩展中国剩余定理(EXCRT)
和普通 C R T CRT CRT 一样有一组同于方程组,只不过模数不一定是质数。
思路也不一样了,是两个同余方程先合并,得到一个 x x x 的解,再依次合并下去。
{ x ≡ b 1 ( m o d a 1 ) x ≡ b 2 ( m o d a 2 ) . . . x ≡ b n ( m o d a n ) \left\{\begin{matrix} x\equiv b_1\pmod{a_1}\\ x\equiv b_2\pmod{a_2}\\ ...\\ x\equiv b_n\pmod{a_n} \end{matrix}\right. xb1(moda1)xb2(moda2)...xbn(modan)
在这里插入图片描述
在这里插入图片描述
代码:

#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const int N = 1e5+5;
int n;
ll s[N],yu[N],ans;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b){x = 1;y = 0;return a;}
    ll g = exgcd(b,a%b,x,y),tp = x;
    x = y;y = tp-a/b*y;
    return g;
}
ll CRT()
{
    ll yu1 = yu[1],s1 = s[1];
    for(int i = 2;i <= n;i++)
    {
        ll yu2 = yu[i],s2 = s[i];
        ll d = yu2-yu1,g,x,y;
        g = exgcd(s1,s2,x,y);
        if(d%g)return -1;
        ll now = s2/g;
        x = (x*(d/g)%now+now)%now;
        yu1 = x*s1+yu1;s1 = s1/g*s2;
    }
    return yu1;
}
int main()
{
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)
        scanf("%lld%lld",s+i,yu+i);
    printf("%lld\n",CRT());
    return 0;
}

3.组合数学

定义:
n n n 个互不相同的物品里面选出 m m m 个排成一列(有先后顺序),总共有多少种选法?
这是一个排列问题,我们将这个方案数定义为 P ( n , m ) P(n,m) P(n,m)
第一次有n种取法,第二次有 n − 1 n-1 n1 种…第 m m m 次有 n − m + 1 n-m+1 nm+1 种,根据乘法原理,方案数应该为 n ! ( n − m ) ! \frac{n!}{(n-m)!} (nm)!n!。即 P ( n , m ) = n ! ( n − m ) ! P(n,m)=\frac{n!}{(n-m)!} P(n,m)=(nm)!n!

那如果没有先后顺序呢?这个方案数就是 C ( n , m ) C(n,m) C(n,m),也可以记作 ( m n ) \binom{m}{n} (nm)
可以发现组合数相对排列数,就只是把顺序去掉了,即 ( 1 , 2 ) (1,2) (1,2) ( 2 , 1 ) (2,1) (2,1) 是同一种选法,把 m m m 个无序的物品排成有序的有 m ! m! m! 种方法,所以 C ( n , m ) = n ! ( n − m ) ! m ! C(n,m)=\frac{n!}{(n-m)!m!} C(n,m)=(nm)!m!n!

关于组合数的性质:

  1. C ( n , 0 ) = 1 C(n,0)=1 C(n,0)=1,不选也是一种方案。
  2. C ( n , m ) = 0   ( n < m ) C(n,m)=0\ (n<m) C(n,m)=0 (n<m)
  3. C ( n , m ) = C ( n , n − m ) C(n,m)=C(n,n-m) C(n,m)=C(n,nm),从 n n n 个里面拿出 m m m 个和留下 n − m n-m nm 个等价。
  4. C ( n , m ) = C ( n − 1 , m − 1 ) + C ( n − 1 , m ) C(n,m)=C(n-1,m-1)+C(n-1,m) C(n,m)=C(n1,m1)+C(n1,m),可以由这条性质 O ( n 2 ) O(n^2) O(n2) 求出杨辉三角。
  5. 可以根据第 4 4 4 条性质推出: ∑ i = m n ( m i ) = ( m + 1 n + 1 ) \sum_{i=m}^{n}\binom{m}{i}=\binom{m+1}{n+1} i=mn(im)=(n+1m+1)
二项式定理

即求 ( x + y ) n (x+y)^n (x+y)n 拆开后各项的系数。
可以单独考虑 x m y n − m x^my^{n-m} xmynm,就是从 n n n ( x + y ) (x+y) (x+y) 中选出 m m m x x x,即 C ( n , m ) C(n,m) C(n,m)
所以 ( x + y ) n = ∑ i = 0 n ( i n ) x i y n − i (x+y)^n=\sum_{i=0}^n\binom{i}{n}x^iy^{n-i} (x+y)n=i=0n(ni)xiyni

应用:

0 n = ( 1 + ( − 1 ) ) n = C ( n , 0 ) − C ( n , 1 ) + C ( n , 2 ) . . . + ( − 1 ) n C ( n , n ) 0^n=(1+(-1))^n=C(n,0)-C(n,1)+C(n,2)...+(-1)^nC(n,n) 0n=(1+(1))n=C(n,0)C(n,1)+C(n,2)...+(1)nC(n,n)
即奇数项之和等于偶数项之和。
2 n = ( 1 + 1 ) n = C ( n , 0 ) + C ( n , 1 ) + . . . + C ( n , n ) 2^n=(1+1)^n=C(n,0)+C(n,1)+...+C(n,n) 2n=(1+1)n=C(n,0)+C(n,1)+...+C(n,n)
即所有项之和为 2 n 2^n 2n
你可以将上面两式相减(加)再除以 2 2 2,就可以求得奇数项(偶数项)之和。

LUCAS

如果要求 C ( n , m ) % p C(n,m)\%p C(n,m)%p,但 n , m n,m n,m 太大时,就可以用 LUCAS。
( m n ) % p ≡ ( ⌊ m p ⌋ ⌊ n p ⌋ ) × ( m % p n % p ) ( m o d p ) \binom mn\%p\equiv\binom{\lfloor\frac mp\rfloor}{\lfloor\frac np\rfloor}\times\binom{m\%p}{n\%p}\pmod p (nm)%p(pnpm)×(n%pm%p)(modp)
n > p n>p n>p m > p m>p m>p 时只要反复对第一部分使用该定理即可
使用条件: p p p 是较小质数
P3807 【模板】卢卡斯定理/Lucas 定理

ll inv[N],fac[N];
int lucas(int n,int m,int p)
{
    if(n < m)return 0;
    if(n < p)return fac[n]*inv[m]*inv[n-m]%p;
    return lucas(n/p,m/p,p)*lucas(n%p,m%p,p)%p;
}
int main()
{
    int T;cin >> T;
    while(T--)
    {
        int n,m,p;scanf("%d%d%d",&n,&m,&p);n += m;
        fac[0] = inv[0] = inv[1] = 1;
        for(int i = 1;i <= n;i++)fac[i]=fac[i-1]*i%p;
        for(int i = 2;i <= n;i++)inv[i]=(p-p/i)*inv[p%i]%p;
        for(int i = 1;i <= n;i++)inv[i]=inv[i-1]*inv[i]%p;
        printf("%d\n",lucas(n,m,p));
    }
    return 0;
}

参考文章:
数论入门知识
题解 P4777 【【模板】扩展中国剩余定理(EXCRT)】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值