数论知识总结
数论知识总结
介绍
1.素数
定义:对于一个正整数,如果它有且仅有 \(1\) 和它自己两个约数,那么我们称这个数为素数。如果有两个以上的约数,那么我们称这个数为合数。
唯一因子分解定理(质因数分解):合数能被唯一的分解为质数的乘积形式:
\(a=p_1^{k_1}p_2^{k_2}...p_r^{k_r},p_1<p_2<...<p_r\)。
如何求素数
- 暴力枚举:\(O(\sqrt n)\)。
- 筛法求素数:用每个素数去筛掉它的倍数,时间 \(O(nlogn)\)。
- 线性筛素数:在筛法的基础上 我们让每一个合数只能被他自己最小的素数筛到。
直接看代码:
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)\) 表示 \(a\) 和 \(b\) 的最大公约数,\(\operatorname{lcm}(a,b)\) 表示 \(a\) 和 \(b\) 的最小公倍数。
求法
知道这两个公式就行了:\(\gcd(a,b)=\gcd(a-b,b)\),\(\operatorname{lcm}(a,b)=\frac{ab}{\gcd(a,b)}\)。
代码:
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为 \(\{ax+by\}\)(\(x,y\in Z\))中的最小正数(\(d\) 的倍数均在集合中且集合中的数都是 \(d\) 的倍数)
一个重要的推论是:\(ax+by=1\) 有解等价于 \(a\) 和 \(b\) 互质。
扩展欧几里得
欧几里得算法只能告诉我们 \(ax+by=m\) 这个方程有没有解(\(\gcd(a,b)\mid m\) 成不成立),而不能说明解是多少,使用扩展欧几里得算法可以解决这个问题。
\(ax+by=d\)
\(b'x+(a\%b)y'=d\)
欧几里得算法是一个递归的过程,那我们也用递归来求解 \(x\) 和 \(y\),现在已知 \(x’\) 和 \(y’\),求 \(x\) 和 \(y\)。
变个形:\(a\%b=a-\lfloor\frac{a}{b}\rfloor\times b\)
然后把含 \(a\) 的和含 \(b\) 的分别凑一块:\(ay'+b(x'-\lfloor\frac{a}{b}\rfloor\times 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\),它在模 \(p\) 意义下的逆元 \(a\),满足 \(ax\equiv 1\pmod p\)。
如何求逆元?
- 扩展欧几里得,这式子不是和 \(ax+by=m\) 长得很像吗?直接做就完了,时间复杂度:\(O(log_{\max(a,b)})\)。
- 费马小定理:若 \(p\) 为素数,则 \(a^{p-1}\equiv1\pmod p\),所以 \(a^{p-2}\) 就是 \(a\) 的逆元,用快速幂就行了。
- 线性求逆元:
将 \(p\) 写成 \(k\times i+r\) 的形式,其中 \(0<r<i\)(即带余除法)。
\(k\times i+r\equiv 0\pmod p\)
两边同时除以 \(r\times i\) 得:\(k\times r^{-1}+i^{-1}\equiv 0\pmod p\)
所以 \(i^{-1}\equiv-k\times r^{-1}\pmod p\)
代码就是:
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\) 就行了。
设 \(M=\prod_{i=1}^km_i\),\(M_i=\frac M{m_i}\),\(t_i\) 为 \(M_i\) 的逆元,则 \(x=\sum_{i=1}^na_iM_it_i\),那么最小解就是 \(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)
和普通 \(CRT\) 一样有一组同于方程组,只不过模数不一定是质数。
思路也不一样了,是两个同余方程先合并,得到一个 \(x\) 的解,再依次合并下去。
代码:
#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\) 个互不相同的物品里面选出 \(m\) 个排成一列(有先后顺序),总共有多少种选法?
这是一个排列问题,我们将这个方案数定义为 \(P(n,m)\)。
第一次有n种取法,第二次有 \(n-1\) 种…第 \(m\) 次有 \(n-m+1\) 种,根据乘法原理,方案数应该为 \(\frac{n!}{(n-m)!}\)。即 \(P(n,m)=\frac{n!}{(n-m)!}\)。
那如果没有先后顺序呢?这个方案数就是 \(C(n,m)\),也可以记作 \(\binom{m}{n}\)。
可以发现组合数相对排列数,就只是把顺序去掉了,即 \((1,2)\) 和 \((2,1)\) 是同一种选法,把 \(m\) 个无序的物品排成有序的有 \(m!\) 种方法,所以 \(C(n,m)=\frac{n!}{(n-m)!m!}\)。
关于组合数的性质:
- \(C(n,0)=1\),不选也是一种方案。
- \(C(n,m)=0\ (n<m)\)。
- \(C(n,m)=C(n,n-m)\),从 \(n\) 个里面拿出 \(m\) 个和留下 \(n-m\) 个等价。
- \(C(n,m)=C(n-1,m-1)+C(n-1,m)\),可以由这条性质 \(O(n^2)\) 求出杨辉三角。
- 可以根据第 \(4\) 条性质推出:\(\sum_{i=m}^{n}\binom{m}{i}=\binom{m+1}{n+1}\)。
二项式定理
即求 \((x+y)^n\) 拆开后各项的系数。
可以单独考虑 \(x^my^{n-m}\),就是从 \(n\) 个 \((x+y)\) 中选出 \(m\) 个 \(x\),即 \(C(n,m)\)。
所以 \((x+y)^n=\sum_{i=0}^n\binom{i}{n}x^iy^{n-i}\)。
应用:
\(0^n=(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\)。
你可以将上面两式相减(加)再除以 \(2\),就可以求得奇数项(偶数项)之和。
LUCAS
如果要求 \(C(n,m)\%p\),但 \(n,m\) 太大时,就可以用 LUCAS。
\(\binom mn\%p\equiv\binom{\lfloor\frac mp\rfloor}{\lfloor\frac np\rfloor}\times\binom{m\%p}{n\%p}\pmod p\)
在 \(n>p\) 或 \(m>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;
}