数论,是信息学竞赛中很重要的一个知识点。最近学习了数论的一些经典问题与算法,还是写写博客总结一下。
1.整除(简单又基本)
定义:设a、b为整数,且b不等于0,若存在整数p使得a=b*p,那么称b整除a,记为b|a
性质:
1)如果a|b,b|c,那么a|c
2)如果a|b,a|c,那么a|(kb+lc) (k、l为整数)
3)如果a|b,那么ma|mb (m≠0)
4)如果存在整数x、y,使得ax+by=1,且a|n,b|n,那么ab|n(因为如果存在x、y满足条件,那么a、b互质,之后的便不难理解)
2.gcd与lcm(较简单)
定义:gcd:最大公约数,lcm:最小公倍数
性质:lcm(a,b)=a*b/gcd(a,b)
计算方式:
因为lcm可以转化为gcd,我们可以只求gcd
我们设a>b,gcd(a,b)=d。我们将a表示为k*b+p,那么d|(k*b+p)、d|b,所以d|p,也就是d|(a%b),因此d也是(a%b)的约数,但d是不是b与(a%b)的最大公约数呢?如果不是,那么一定存在一个更大的d'|b且d'|(a%b),那么d'|a,与d是a,b的最大公约数相矛盾。所以:gcd(a,b)=gcd(b,a%b)这就是欧几里得算法
3.勾股数(有一些难度)
定义:若存在整数x、y、z,使得x^2+y^2=z^2,那么称(x,y,z)为一组勾股数,如果x、y、z可以由一组勾股数分别乘上一个数得到,那么就称之为派生勾股数,否则叫基本勾股数,基本勾股数满足gcd(x,y,z)=1
性质:
基本勾股数的奇偶性:
1)三个偶数
明显不行,因为如果是三个偶数,至少是派生的,可以一起除以2
2)三个奇数
也不行,奇数平方=奇数,奇数+奇数≠奇数
3)一奇两偶
不行,不管是偶+偶还是奇+偶都无法得到合法解(偶+偶≠奇,奇+偶≠偶)
4)两奇一偶
唯一的方法,如果x奇y奇,那么x=2k+1,y=2p+1,x^2=4k^2+4k+1,y^2=4p^2+4p+1,那么(x^2+y^2)%4=2,无法开方,所以勾股数必定是奇+偶=奇!
计算方法:x=m,y=(m^2/k-k)/2,z=(m^2/k+k)/2,
① 当m确定为任意一个≥3的奇数时,k={1,m^2的所有小于m的因子}
② 当m确定为任意一个 ≥4的偶数时,k={m^2 / 2的所有小于m的偶数因子})
4.素数(质数)(较简单)
定义:因子只有1与本身的数称为素数
判断素数:O(sqrt(n))
枚举2~sqrt(n),如果都不是n的因子,那么n是素数
筛素数:
一般方法:
int vis[MAXN];
int prime[MAXP]
void sieve(int n)
{
int m=(int)sqrt(n+0.5); //浮点数四舍五入,最好在后面加一个0.5。
memset(vis,0,sizeof(vis));
for(int i=2;i<=m;i++)
if(!vis[i])
for(int j=i*i;j<=n;j+=i)
vis[j]=1;
极速方法(巧妙运用循环):
int prime[MAXP];
bool flag[MAXN];
int j=0;
for(int i=2;i<=n;i++)
{
if(flag[i]==0)
prime[j++]=i;
for(int k=0;k<j;k++)
{
if(prime[k]*i>n)break;
flag[prime[k]*i]=1;
if(i%prime[k]==0)break;
}
}
5.同余
定义:如果a%n=b%n,称a与b关于n同余,写作a≡b(mod n)
性质:
1.自反性:a≡a(mod m)
2.对称性:若a≡b(mod m),则b≡a(mod m)
3.传递性:若a≡b(mod m),b≡c(mod m),则a≡c(mod m)
4.同加性:若a≡b(mod m),则a+c≡b+c(mod m)
5.同乘性:若a≡b(mod m),则a*c≡b*c(mod m),若a≡b(mod m),c≡d(mod m),则有a*c≡b*d(mod m)
6.同幂性:若a≡b(mod m),则an≡bn(mod m)
7.若a%p=x,a%q=x,且p,q互质,则a%(p*q)=x
三大分配率:
加法分配率:(a+b)%n=(a%n+b%n)%n
减法分配率:(a-b)%n=(a%n-b%n)%n
乘法分配率:(a*b)%n=a%n*b%n%n
相关定理:
1)威尔逊定理:如果p为质数,(p-1)!≡-1(mod p)
证明:p为质数,1~p-1全在p的缩系中,除了1和p-1与自己配对,其他两两与别的数配对后%p=1,那么(p-1)!只剩下p-1和1,相乘后%p=p-1
2)欧拉定理(费马小定理含于欧拉定理):如果a与m互质,a^φ(m)≡1(mod m)
证明:设φ(m)=p,这个证明,无非是证明a^p%m=1。我们已经知道,对于一个整数都会有缩系,而欧拉函数刚好(或是专门)用来求一个数的缩系中元素个数。我们可以将a^p乘上m的缩系中的每个元素,转化为如下形式:(a*k1%m+a*k2%m+a*k3%m+...+a*kp%m)%m,而对于不相等的i和j,且a与m互质,有:a*ki%m≠a*kj%m且它们都在m的缩系中,那么原式的值也等于(k1*k2*k3*...*kp)%m,即a^p*k1*k2*k3*...*kp≡k1*k2*k3*...*kp(mod m),由缩系的定义,我们可以得知:k1*k2*k3*...*kp与m互质,那么两边同时除以一个k1*k2*k3*...*kp,就有了a^p%m=1
相关:
求欧拉函数
1.求单个欧拉函数
int euler(int n)
{
int m=(int)sqrt(n+0.5);
int ans=n;
for(int i=2;i<=m;i++)
{
if(n%i==0)
{
ans=ans/i*(i-1);
while(n%i==0)
n/=i;
}
}
if(n>1)
ans=ans/n*(n-1);
}
2.求1~n所有欧拉函数
int phi[maxn];
void phi_table(int n)
{
phi[1]=1;
for(int i=2;i<=n;i++)
if(!phi[i])
for(int j=i;j<=n;j+=i)
{
if(!phi[j])
phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
3)扩展欧几里得定理:ax+by=gcd(a,b)一定有解,可以求出这个解
证明:设d=gcd(a,b),因为ax+by=d一定有解,d=gcd(a,b)=gcd(a,a%b),所以bx1+a%b*y1=d也一定有解,以下是证明过程:
bx1+a%b*y1=d =>
bx1+(a-a/b*b)*y1=d =>
bx1+ay1-a/b*b*y1=d =>
ay1+b*(x1-a/b*y1)=d
根据原式:ax+by=d,显然:当x=y1,y=x1-a/b*y1时一定是一组解,那么递归求解即可
相关:
求解二元一次方程
ax+by=c,显然只有c=k*d(gcd(a,b))时才有解,算出ax+by=d时的解,然后c是d的几倍,x和y就乘以几,解答完毕……
求解模线性方程
ax≡b(mod n),转化一下,变成ax+ny≡k*d(即gcd(a,n))(mod n)(当然,b如果不是d的倍数自然无解),我们可以求出ax+ny≡d(mod n)时的一个x,然后将它乘上k求出一个解。那么怎么求最小的x(x0)呢?显然:
ax+ny≡b =>
ax+l+ny-l≡b =>
a(x+l/a)+n(y-l/n)≡b
所以,l如果是a、n的公倍数,要使得l最小,那l就是a、n的最小公倍数,即a*n/d。对于a而言,x就加上了一个a*n/d/a即n/d,那么只要不停加或减n/d得到的x,都是方程的解。所以x0=(x%(n/d)+n/d)%n/d,就可以顺利解答所有情况了!
未完待续。。。