目录
整除
1.定义
如果\(a\)能把\(b\)除尽,则我们称\(a\)整除\(b\),也称\(b\)被\(a\)整除,记为:\(b | a\)。
2.整除的性质
自反性:\(n | n(n≠0)\)
传递性:若有\(a | b\),\(b | c\),则有\(a | c\)
对称性:若\(a | b\),\(b | a\),则\(a=b\)
质数
1.定义
没有真因子(大于1而小于本身)的数。
2.个数:无限个
证明(反证法):
假设质数个数是有限的,则必有一最大质数\(p_m\)。
设\(n=p_1\cdot p_2 \cdot p_3 \cdot \cdots \cdot p_m+1\),\(n\)是合数。
我们发现\(n\)不能被任何一个质数整除,因此\(n\)也是质数,这与"质数有有限个"矛盾。
说明假设不正确,则原命题得证。
我们记\([1,n]\)中的质数个数为\(\pi(n)\),则有:\(\pi(n)\)~\(\frac{n}{\ln n}\)(\(\lim_{n\rightarrow\infty}\frac{\pi(n)}{n/\ln n}=1\))
3.算术基本定理
任何一个正整数的质因数分解是唯一的,为\(N=p_1^{r_1} \cdot p_2^{r_2} \cdot p_3^{r_3} \cdot\cdots\)。
4.质因数分解性质
将一个数\(n\)质因数分解,那么它最多被拆成\(\log_2n\)个质数(最坏情况为\(2^n=\overbrace{2\times2\times2\times \cdots \times 2}^{\log_2n}\))
5.质因数分解表示正整数乘法(除法)
如果\(A=2^{a_1}\times3^{a_2}\times5^{a_3}\times\cdots\),\(B=2^{b_1}\times3^{b_2}\times5^{b_3}\times\cdots\),
则\(A/B=2^{a_1-b_1}\times3^{a_2-b_2}\times5^{a_3-b_3}\times\cdots\),\(A\times B=2^{a_1+b_1}\times3^{a_2+b_2}\times5^{a_3+b_3}\times\cdots\)
6.一个数约数的个数
如果一个数\(n\)可以分解为\(n=p_1^{r_1}\cdot p_2^{r_2}\cdots=\prod_{i=1}^kp_i^{r_i}\),则它的约数个数为\(f(n)=(r_1+1)(r_2+1)\cdots=\prod_{i=1}^k(r_i+1)\)
7.判断质数
暴力枚举(时间复杂度:\(O(\sqrt{n})\))
bool is_prime(int x)
{
if(x==1) return false;
for(int i=2;i*i<=x;i++)
if(!(x%i)) return false;
return true;
}
8.质因数分解
①: 暴力枚举(时间复杂度\(O(\sqrt{n})\))
算法原理:一个数大于\(\sqrt{n}\)的质因数最多一个。
证明(反证法):
假设\(n\)有两个大于\(\sqrt{n}\)的质因子\(p_1,p_2\),
那么\(lcm(p1,p2)\),即\(p_1p_2\)一定是\(n\)的因子,
由于\(p_1,p_2\)都大于\(\sqrt{n}\),因此\(p_1p_2>n\),不可能是\(n\)的因子,这与"假设\(n\)有两个大于\(\sqrt{n}\)的质因子"矛盾,
说明假设不正确,则原命题得证。
因此,只需考虑\([2,n]\)中的质数即可。
int getDivisor(int x,int p[])//将x分解质因数,将结果从小到大储存在p[]中,并返回质因子个数
{
int cnt=0;
for(int i=2;i*i<=x;i++)//从2枚举到sqrt(x)
{
//如果找到一个约数,就不断从x中除去
while(!(x%i))
{
p[cnt++]=i;
x/=i;
}
}
//如果x>1,说明剩下的x是质数,也要放进数组
if(x>1) p[cnt++]=x;
return cnt;
}
9.质数筛法
①对于每个数,直接判断是否是质数
②埃氏筛法:把不大于\(\sqrt{n}\)的所有素数的倍数筛除,剩下的就是质数
时间复杂度:\(O(nlog_2log_2n)\)
const int MAXN=10000005;
int prime[MAXN];
bool is_prime[MAXN];
void Make_Prime(int n)//筛出2-n的质数
{
int p=0;
memset(is_prime,true,sizeof(is_prime));
is_prime[0]=is_prime[1]=false;
for(int i=2;i<=n;i++)
if(is_prime[i])
{
prime[p++]=i;
for(int j=2*i;j<=n;j+=i) is_prime[j]=false;
}
}
③:欧拉筛法(线性筛):让每个数只被它的最小质因子筛除
时间复杂度:\(O(n)\)
const int Maxn=10000005;
int prime[Maxn];
bool isprime[Maxn];
void make_prime(int a)
{
int p=0;
for(int i=0;i<a;i++) isprime[i]=true;
isprime[0]=isprime[1]=false;
for(int i=2;i<=a;i++)
{
if(isprime[i]) prime[p++]=i;
for(int j=0;j<p&&i*prime[j]<a;j++)
{
isprime[i*prime[j]]=false;
if(!(i%prime[j])) break;
}
}
return;
}
最大公约数和最小公倍数
公约数
设\(n=p_1^{a_1}\cdot p_2^{a_2}\cdot p_3^{a_3}\cdots,m=p_1^{b_1}\cdot p_2^{b_2}\cdot p_3^{b_3}\cdots,d=p_1^{c_1}\cdot p_2^{c_2}\cdot p_3^{c_3}\cdots\),若\(c_i\leq min(a,b)\),则\(d\)是\(n\)和\(m\)的公约数。
最大公约数
\(gcd(a,b)=p_1^{min(a_1,b_1)}\cdot p_2^{min(a_2,b_2)}\cdot p_3^{min(a_3,b_3)}\cdots\)
最小公倍数
\(lcm(a,b)=p_1^{max(a_1,b_1)}\cdot p_2^{max(a_2,b_2)}\cdot p_3^{max(a_3,b_3)}\cdots\)
性质
\(gcd(a,b)\cdot lcm(a,b)=a\cdot b\)
证明:
设\(a_i<b_i\),
\(\because gcd(a,b)=p_1^{min(a_1,b_1)}\cdot p_2^{min(a_2,b_2)}\cdot p_3^{min(a_3,b_3)}\cdots,lcm(a,b)=p_1^{max(a_1,b_1)}\cdot p_2^{max(a_2,b_2)}\cdot p_3^{max(a_3,b_3)}\cdots\),
\(\therefore gcd(a,b)=p_1^{a_1}\cdot p_2^{a_2}\cdot p_3^{a_3}\cdots,lcm(a,b)=p_1^{b_1}\cdot p_2^{b_2}\cdot p_3^{b_3}\cdots\)
\(\therefore gcd(a,b)\cdot lcm(a,b)=p_1^{a_1+b_1}\cdot p_2^{a_2+b_2}\cdot p_3^{a_3+b_3}\cdots=a\cdot b\)
\(Q.E.D.\)
注:
int lcm=a*b/gcd(a,b);
这样可能会爆int
应写成
int lcm=a/gcd(a,b)*b;
求最大公约数
1.辗转相除法(GCD递归定理/欧几里得算法)
\(gcd(a,b)=gcd(b , a\% b)\)
证明:
根据整除的对称性,只要证明\(gcd(a,b) | gcd(b,a \% b)\)且\(gcd(b,a\% b) | gcd(a,b)\),即可证明。
①:设\(gcd(a,b)=k\),则可设\(a=pk,b=qk,且p\bot q\),此时要证\(k | gcd(qk,pk\% qk)\)。
\(\because pk\% qk=k(p\% q),且p\bot q\)
\(\therefore p\% q ≠0\)
\(\therefore pk\% qk\)是\(k\)的正整数倍,\(gcd(qk,pk\% qk)\)亦是\(k\)的正整数倍。
\(\therefore gcd(a,b) | gcd(b,a\% b)\)。
②:设\(gcd(b,a\% b)=d\),则可设\(b=rd,a\% b=td\),且\(r\bot t\)。
设\(a\div b\)的商是\(w\),则\(a=wb+td=wrd+td=(wr+t)d\)
\(\therefore d | a\)
又\(\because d | b\)
\(\therefore d |gcd(a,b)\),即\(gcd(b,a\% b)|gcd(a,b)\)。
\(Q.E.D.\)
代码:
inline int gcd(int a,int b)
{
return !b?a:gcd(b,a%b);
}
2.更相减损术
\(gcd(a,b)=gcd(b,a-b)\)
证明:
设\(gcd(a,b)=k,a=pk,b=qk,p\bot q\)。
\(\therefore gcd(b,a-b)=gcd(qk,(p-q)k)\)
\(\because p\bot q\)
\(\therefore p\bot p-q\Rightarrow q\bot p-q\)
\(\therefore gcd(qk,(p-q)k)=k\)
\(gcd(a,b)=gcd(b,a-b)\)
\(Q.E.D.\)
代码:
inline int gcd(int a,int b)
{
while(a!=b)
if(a>b) a-=b;
else b-=a;
return a;
}
3.Stein算法
设\(x,y\)为非0奇数,则有以下结论:
\(1.gcd(x,0)=x\)
\(2.gcd(2x,2y)=2(gcd,x,y)\)
\(3.gcd(2x,y)=gcd(x,y)\) \(gcd(x,2y)=gcd(x,y)\)
\(4.gcd(x,y)=gcd(|x-y|,min(x,y))\)
算法原理:运用上述结论使两数皆为奇数,再用更相减损术求出两数最大公倍数,再乘上结论2中所除的\(k\)个2。
代码:
inline int stein(int a,int b)//递归
{
if(a<b) a^=b,b^=a,a^=b;//用异或运算^交换两数
if(!b) return a;
if(!(a&1)&&!(b&1)) return stein(a>>1,b>>1)<<1;
else if(!(a&1)) return stein(a>>1,b);
else if(!(b&1)) return stein(a,b>>1);
//用按位与&判断两数奇偶
else return stein(a-b,b);
}
inline int stein(int a,int b)//循环
{
int k=1;
while(!(a&1)&&!(a&1))
{
k<<=1;
a>>=1;
b>>=1;
}
while(!(a&1)) a>>=1;
while(!(b&1)) b>>=1;
while(a!=b)
{
a-=b;
if(a<b) a^=b,b^=a,a^=b;
}
return k*a;
}
另一个性质
记\(F[n]\)为斐波那契数列的第\(n\)项,则有:
\(gcd(F[a],F[b])=F[gcd(a,b)]\)
模
1.取整
\(\lfloor x\rfloor\)表示不超过\(x\)的最大整数,有:
\(\forall a \in R,n=\lfloor a \rfloor\)的值域为\(\{n \in Z|n\leq a<n+1\}\)
\(\lceil x \rceil\)表示不小于\(x\)的最小整数,有:
\(\forall a \in R,n=\lceil a \rceil\)的值域为\(\{n \in Z|n-1<a\leq n\}\)
2.除法的表示
\(a=\lfloor\frac{a}{p}\rfloor\times p+a \% p\),其中\(p\)是除数,\(\lfloor\frac{a}{p}\rfloor\)是商,\(a \%p\)是余数
\(\Downarrow\)
\(p | a\)当且仅当\(a\% p=0\)
3.取整性质
① \(\lfloor n+x \rfloor=n+\lfloor x\rfloor,\forall x \in R,\forall n \in Z\);\(\lceil n+x \rceil=n+\lceil x \rceil,\forall x\in R,\forall n\in Z\)
② \(\forall n \in Z,\lfloor \frac{n}{2} \rfloor+\lceil \frac{n}{2} \rceil=n\)
略证:
(1).\(n=2k,k \in Z:\lfloor \frac{n}{2} \rfloor=\lceil \frac{n}{2} \rceil=k\),结论显然成立。
(2).\(n=2k+1,k \in Z:\lceil \frac{n}{2} \rceil=k+1,\lfloor \frac{n}{2} \rfloor=k\),结论依然成立。
③ \(\lfloor\frac{a}{bc}\rfloor=\lfloor\frac{\lfloor\frac{a}{b}\rfloor}{c}\rfloor,\forall a\in(0,+\infty),b,c\in Z^+\)
略证:
设\(\frac{a}{b}=\lfloor \frac{a}{b}\rfloor+r(0\leq r<1)\),
\(\therefore \lfloor\frac{a}{bc}\rfloor=\lfloor \frac{a}{b} \cdot \frac{1}{c} \rfloor=\lfloor \frac{1}{c}(\lfloor \frac{a}{b}+r)\rfloor=\lfloor \frac{\lfloor \frac{a}{b}\rfloor}{c}+\frac{r}{c}\rfloor=\lfloor\frac{\lfloor \frac{a}{b}\rfloor}{c}\rfloor\)
** ④\([1,a]\)中\(b\)的倍数共有\(\lfloor \frac{a}{b}\rfloor\)个 **
⑤\(\lceil \frac{m}{n}\rceil=\lfloor \frac{m-1}{n}\rfloor+1,0<n\leq m,\forall m,n\in Z\)
4.模的性质
①值域:\(a\% p\)一定落在\([0,p-1]\)之间
剩余系:对于一个正整数\(n\),一个整数集模\(n\)所得余数的集合。
完全剩余系:如果一个剩余系包含了一个正整数\(n\)所有可能的余数\((0,1,\cdots n-1)\),则称它是模\(n\)的一个完全剩余系。
简化剩余系:一个\(n\)的完全剩余系中与\(n\)互质的元素组成的子集。
例:模10的一个简化剩余系为1,3,7,9
②"随时取模":
在只含加法和乘法的式子中,如果最后的运算结果需要对\(p\)取模,那么可以在运算过程中随便取模,只要最后把结果对\(p\)再取模,结果就是正确的。
即:
\((a+b)\% p=(a\% p+b\% p)\% p\)
\((ab)\% p=[(a\% p)\cdot(b\% p)]\% p\)
5.随时取模的应用
①正整数\(n\)被3整除,当且仅当十进制下\(n\)的各位数字之和被3整除。
证明:
考虑三位数的\(n\):
设\(n=\overline{abc}\),则有\(n\% 3=(100a+10b+c)\% 3\)
\(=[(100\% 3)a+(10\% 3)b+c]\% 3\)
\(=(a+b+c)\% 3\)
也就是说:\(n\% 3=0\)等价于\((a+b+c)\% 3=0\)
其他位数的\(n\)同理。
\(Q.E.D.\)
②\(n\)被4整除当且仅当其最后两位数被4整除。
证明:
设\(n=\overline{abcd}\),则有\(n\% 4=(1000a+100b+10c+d)\% 4\)
\(= (10c+d)\% 4\)
\(=\overline{cd}\% 4\)
其他位数的\(n\)同理。
\(Q.E.D.\)
6.逆元
有理数意义下,我们可以把\(a\div b\)转化为\(a\times\frac{1}{b}\),此时我们称\(b\)和\(\frac{1}{b}\)互为倒数。
模意义下,这样的数叫做数论倒数,或者逆元。
若记\(inv(x)\)为\(x\)的逆元,则在模\(p\)意义下有:\(x\cdot inv(x)\equiv 1\pmod p\)
注意:\(x\)有关于\(p\)的逆元,当且仅当\(x\bot p\)。
不定方程
裴蜀定理
若\(a,b\)是整数,且\(gcd(a,b)=d\),那么对于任意的整数\(x,y,ax+by\)都一定是\(d\)的倍数,特别地,一定存在整数\(x,y\),使\(ax+by=d\)成立。
$\Downarrow $
关于整数\(x,y\)的不定方程\(ax+by=gcd(a,b)\),必然有解。
扩展欧几里得算法
Exgcd是一种求解不定方程\(ax+by=gcd(a,b)\)的算法,可以运用它来解同余方程。
有定理1:"方程\(ax+by=c\)和\(ax\equiv c \pmod b\)是等价的,有整数解的充要条件为\(gcd(a,b)|c\)",因此可以用Exgcd先求出\(ax+by=gcd(a,b)\)的一组解\(x_0,y_0\),两边再同时\(*c/gcd(a,b)\),就得到了方程的一组解。
有定理2:"若\(gcd(a,b)=1\),且\(x_0,y_0\)为方程\(ax+by=c\)的一组解,则该方程的通解为\(x=x_0+bt,y=y_0+at(t\in Z)\)",由此可以求出方程所有解。
但是问题中一般会询问最小正整数解\(x\),若设\(m=b/gcd(a,b)\),令\(x=(x\% m+m)\%m\)即可。
重点:
1.判断无解:\(c\%gcd(a,b) \neq0\)
2.\(x\)的最小正整数解:设\(m=b/gcd(a,b)\),令\(x=(x\% m+m)\%m\)
算法思想:
"如果知道了\(bx+(a\)% \(b)y=gcd(a,b)\)的解\((x,y)\),如何求出
\(ax'+by'=gcd(a,b)\)的解\((x',y')\)?
设\(gcd(a,b)=d\)
此时a%b可以表示成\(a-\lfloor\frac{a}{b}\rfloor\cdot b\)
所以\(ay+b(x-\lfloor\frac{a}{b}\rfloor\cdot y)=d\)
令\(x'=y,y'=x-\lfloor\frac{a}{b}\rfloor\cdot y\)即可。''
代码:
int x,y;
inline void exgcd(int a,int b)
{
if(!b)
{
x=1,y=0;
return;
}
exgcd(b,a%b);
int tx=x;
x=y;
y=tx-a/b*y;
}
中国剩余定理
\[\begin{cases} x\equiv a_1\pmod {m_1}\\ x\equiv a_2\pmod {m_2}\\ \cdots\\ x\equiv a_n\pmod {m_n} \end{cases}\]
若满足\(m_1,m_2,\cdots m_n\)两两互质,则可用中国剩余定理(CRT)求解。
构造法:
设\(M=\prod_{i=1}^nm_i,M_i=M/m_i\),则方程通解为\(x=\sum_{i=1}^na_i\cdot inv(M_i)\cdot M_i+kM,k\in Z\),其中模\(M\)意义下有唯一解\(x=\sum_{i=1}^na_i\cdot inv(M_i)\cdot M_i\)。
代码:(Luogu P3868 猜数字)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL x,y,a[15],m[15];
inline LL read()
{
LL x=0,f=1;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
do{x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}while(isdigit(ch));
return f*x;
}
inline void exgcd(LL a,LL b)
{
if(!b){x=1,y=0;return;}
exgcd(b,a%b);
int tx=x;
x=y;
y=tx-a/b*y;
}
inline LL Qmul(LL a,LL b,LL m)
{
LL ans=0;
while(b)
{
if(b&1) ans=(ans+a)%m;
a=(a+a)%m;
b>>=1;
}
return ans;
}
LL CRT(int n)
{
LL ans=0,M=1;
for(int i=1;i<=n;i++) M*=m[i];
for(int i=1;i<=n;i++)
{
LL Mi=M/m[i];
exgcd(Mi,m[i]);
x=(x%m[i]+m[i])%m[i];
ans=(ans+Qmul(Qmul(Mi,x,M),a[i],M))%M;
}
return (ans+M)%M;
}
int main()
{
int k=read();
for(int i=1;i<=k;i++) a[i]=read();
for(int i=1;i<=k;i++) m[i]=read();
for(int i=1;i<=k;i++) a[i]=(a[i]%m[i]+m[i])%m[i];
cout<<CRT(k);
return 0;
}
扩展中国剩余定理(模数不互质)
假设已经求出前\(k-1\)个方程组成的方程组的一个解为\(x\),且有\(M=\prod^{k-1}_{i=1}m_i(LCM^{k-1}_{i=1}m_i)\),则前\(k-1\)个方程的方程组通解为\(x+i*M(i\in Z)\),那么对于加入第\(k\)个方程后的方程组,就要求一个正整数\(t\)使得\(x+t*M\equiv a_k\pmod {m_k}\Rightarrow t*M\equiv a_k-x\pmod {m_k}\Rightarrow t*M+i*m_k=a_k-x\)。若有解,可求出\(t*M+i*m_k=gcd(M,m_k)\),两边再同乘\((a_k-x)/gcd(M,m_k)\)即得解。如此不断循环即可。
代码:(Luogu P4777)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n,x,y,A[100005],B[100005];
inline LL read()
{
LL x=0,f=1;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
return f*x;
}
inline LL exgcd(LL a,LL b)
{
if(!b){x=1,y=0;return a;}
LL gcd=exgcd(b,a%b);
LL tx=x;
x=y;
y=tx-a/b*y;
return gcd;
}
inline LL Qmul(LL a,LL b,LL M)
{
LL ans=0;
while(b)
{
if(b&1) ans=(ans+a)%M;
a=(a+a)%M;
b>>=1;
}
return ans;
}
LL Excrt()
{
LL M=B[1],ans=A[1];
for(int i=2;i<=n;i++)
{
LL a=M,b=B[i],c=(A[i]-ans%b+b)%b;
LL gcd=exgcd(a,b);
//if(c%gcd) return -1;
x=Qmul(x,c/gcd,b/gcd);
ans+=x*M;
M*=b/gcd;
ans=(ans%M+M)%M;
}
return (ans%M+M)%M;
}
int main()
{
n=read();
for(int i=1;i<=n;i++) B[i]=read(),A[i]=read();
cout<<Excrt();
return 0;
}
求逆元方法
模质数意义下
1.费马小定理
\(a^{p-1}\equiv1\pmod p\Rightarrow a\cdot a^{p-2}\equiv1\pmod p\Rightarrow a^{p-2}\equiv inv(a) \pmod p\)
因此,\(a^{p-2}\%p\)就是\(a\)的逆元,此时可套用快速幂求解。
代码:
long long Qpow(long long a,long long n,long long m)
{
unsigned long long t=1;
if(!n) return 0;
while(n>0)
{
if(n&1) t=t*a%m;
a=a*a%m;
n>>=1;
}
return t;
}
inline long long Ginv(long long x,long long p){return Qpow(x,p-2,p);}
2.线性递推求逆元
递推式:\(inv[i]=(p-p/i)*inv[p\%i]\%p\)
代码:
void Ginv(int p)
{
inv[1]=1;
for(int i=2;i<p;i++) inv[i]=(p-p/i)*inv[p%i]%p;
}
非模质数意义下
扩展欧几里得:
\(ax\equiv1\pmod b\Rightarrow ax=kb+1\Rightarrow ax+kb=1\)
此时已知\(a,b\),即可用Exgcd求解,求出的\(x\)即为\(a\)在模\(b\)意义下的逆元。
代码:(Luogu P1082 同余方程)
#include<bits/stdc++.h>
using namespace std;
long long x,y;
inline long long read()
{
long long f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
do{x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}while(isdigit(ch));
return f*x;
}
inline void exgcd(long long a,long long b)
{
if(!b)
{
x=1,y=0;
return;
}
exgcd(b,a%b);
long long tx=x;
x=y;
y=tx-a/b*y;
}
inline long long getinv(long long a,long long b)
{
a%=b;
if(a<0) a+=b;
return a;
}
long long a,b;
int main()
{
a=read(),b=read();
exgcd(a,b);
cout<<getinv(x,b);
return 0;
}