数论其一

一、质数

1.质数的定义:

如果一个正整数无法被除了1和它本身以外的任何自然数整除,那么这个数是质数。否则,这个数是合数。

需要注意的是,1既不是质数也不是合数。

2.埃筛:

2.埃筛:
问题:给定一个正整数 n ,找到1n中的所有质数。

思路:我们可以从 2 开始,从小到大扫描每个数。如果当前的数 x 是质数,就把它的不超过 n 的倍数2x,3x......全部标记为合数。最后所有未被标记的数就是质数。

时间复杂度O(n log log n)

for(int i=2;i<=n;++i)
	if(!vis[i])
		for(int j=i*2;j<=n;j+=i)
			vis[j]=1;

3.欧拉筛:

在埃筛中,一个合数会被多次标记,如6会被2和3分别标记一次。

而欧拉筛运用“每个合数只会被它的最小质因数筛一次”的思想,将时间复杂度降低到了O(n)

思路:设一个数组vv[i]表示 i 的最小质因数。将 2n 扫描一遍。设当前的数是i:如果v[i]=0,说明 i 是质数,令 v[i]=i ,并统计到答案中。接下来扫描不大于 v[i] 的每个质数p,令v[i×p]=p

for(int i=2;i<=n;++i){
	if(v[i]==0)
		v[i]=i,ans[++m]=i;
	for(int j=1;j<=m;++j){
		if(ans[j]>v[i]||ans[j]>n/i)
			break;
		v[i*ans[j]]=ans[j];
	}
}

二、同余

1.定义:

如果整数 a 和整数 b 除以正整数 m 的余数相等,那么称 a,bm 同余,记为:

ab(mod m)

2.同余的性质:

(1)反身性:ab(mod m)ba(mod m)

(2)传递性:ab(mod m),bc(mod m)ac(mod m)

(3)可加性:ab(mod m),cd(mod m)a+cb+d(mod m)

(4)等幂性:ab(mod m)anbn(mod m)

(5)可约性:acbc(mod m),gcd(c,m)=1ab(mod m)

3.欧几里得算法与扩展欧几里得算法:

欧几里得算法:

a,bN,b0,gcd(a,b)=gcd(b,a%b)

证明:

a<b,则 gcd(b,a%b)=gcd(b,a)=gcd(a,b)

ab,不妨设 a=kb+r ,其中0r<b。显然r=a%b。对于a,b的任意公约数dd|ad|kbd|(akb)d|r。因此db,r的公约数。

对于 b,r 的任意公约数 d,也能推出 da,b 的公约数。

因此 a,b 的公约数集合和 b,r 的公约数集合相同。所以它们的最大公约数相等。

证毕。

int gcd_(int a,int b){
	if(b==0)
		return a;
	return gcd_(b,a%b);
}

扩展欧几里得算法:

前置知识:裴蜀定理:

a,bN,x,y 使得 ax+by=gcd(a,b)

证明:

在欧几里得定理的最后一步,即 b=0 时,显然有一对整数 x=1,y=0,使得a×1+0×0=gcd(a,0)=a.

假设存在一对正整数 x,y,满足 bx+(a%b)y=gcd(b,a%b)。那么这时需要证明存在一对正整数x , y ,满ax+by=gcd(a,b).

我们把bx+(a%b)y=gcd(b,a%b)拆开,也就是bx+(abab)y=gcd(b,a%b)

也就是ay+b(xaby))=gcd(b,a%b)。这时,只要令x=y,y=xaby,就能得到ax+by=gcd(a,b).

证毕。

裴蜀定理的证明,实际上给出了整数x,y的计算方法。这种计算方法就是扩展欧几里得算法。

对于更为一般的方程ax+by=c,它有解当且仅当gcd(a,b)|c。我们可以先求出ax+by=gcd(a,b)的一组解x0,y0,然后令x0,y0,同时乘以c/gcd(a,b),就能求得ax+by=c的一组特解。

那么ax+by=c的通解就是:

x=cgcd(a,b)x0+kbgcd(a,b),y=cgcd(a,b)y0kagcd(a,b)

void exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1;y=0;
        return ;
    }
    exgcd(b,a%b,x,y);
    int tmp=x;x=y;y=tmp-a/b*y;
}

P1516 青蛙的约会

题目可以转化为 x+tmy+tn(mod l) ,令a=xyb=nm,则 atb(mod l) 。然后就可以解线性同余方程了。注意负数的情况。

void exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1;y=0;
        return ;
    }
    exgcd(b,a%b,x,y);
    int tmp=x;x=y;y=tmp-a/b*y;
}
signed main(){
    scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l);
    a=n-m;b=x-y;
    if(a<0)
        a=-a,b=-b;
    if(b<0)
        b=(b+l)%l;
    if(b%__gcd(a,l)!=0){
        printf("Impossible\n");
        return 0;
    }
    exgcd(a,l,t,t1);
    t=b/__gcd(a,l)*t;
    t=(t%(l/__gcd(a,l))+(l/__gcd(a,l)))%(l/__gcd(a,l));
    printf("%lld\n",(t%l+l)%l);
    return 0;
}

4.逆元

如果ax1(mod m),且 am 互质,那么 xa 的模 m 乘法逆元

逆元的求法1:扩展欧几里得

我们只要将同余柿子转化成a×x+m×y=1,然后求解方程即可

逆元的求法2:费马小定理

费马小定理:若 m 是质数,且 a,m 互质,则 am11(mod m).

所以am2×a1(mod m). 所以我们要求的 x 就是am2

注意:这种求法只适用于m是质数的情况。

逆元的求法3:线性算法

首先我们知道:111(mod p).

p=ki+r,(1<r<i<p),所以ki+r0(mod p)

两边乘以i1r1可得:kr1+i10(mod p)

i1kr1(mod p)

i1pi×(p mod i)1(mod p)

int main(){
	scanf("%d%lld",&n,&P);
	inv[1]=1;
	for(int i=2;i<=n;i++)
		inv[i]=(P-(P/i))*inv[P%i]%P;
	for(int i=1;i<=n;++i)
		printf("%lld\n",inv[i]);
	return 0;
}

5.中国剩余定理和扩展中国剩余定理:

中国剩余定理:

a1,a2,...,an,是两两互质的整数,a=Πi=1nai,Ai=a/ai,ti 是线性同余方程Aiti1(mod ai)的一个解。

则对于任意的 n 个整数b1,b2,...,bn,方程组

{xb1(mod a1)xb2(mod a2)...xbn(mod an)

有整数解,解为x=i=1nbiAiti

证明:
原方程组可以拆解成为n个方程组:

{x1b1(mod a1)x10(mod a2)...x10(mod an){x20(mod a1)x2b2(mod a2)...x20(mod an)...{xn0(mod a1)xn0(mod a2)...xnbn(mod an)

即:

{x1b1(mod a1)x10(mod A1){x2b2(mod a2)x20(mod A2)...{xnbn(mod an)xn0(mod An)

此时原方程组的解为:x=i=1nxi

xi=Aiki,则第 i 个方程组就转化为Aikibi,(mod ai)

由题目可知,Aiti1(mod ai),所以ki=tibi

所以xi=Aitibi,所以整个方程组的解就是x=i=1nbiAiti

证毕。

ll exgcd(ll &x,ll &y,ll a,ll b){
	if(b==0){
		x=1;y=0;return a;
	}		
	ll re=exgcd(x,y,b,a%b);
	ll tmp=x;x=y;y=tmp-a/b*y;
	return re;
}
int main(){
	scanf("%lld",&n);
	s=1;
	for(int i=1;i<=n;++i){
		scanf("%lld%lld",&a[i],&b[i]);
		s*=a[i];
	}
	for(int i=1;i<=n;++i){
		exgcd(x,y,s/a[i],a[i]);
		x=s/a[i]*((x+a[i])%a[i])*b[i];
		ans=(ans+x)%s;
	}
	printf("%lld\n",ans);
	return 0;
}

扩展中国剩余定理:

还是求解中国剩余定理的方程组,但不保证m1,m2,...,mn 两两互质。

我们可以通过合并相邻方程的方式求解。

随便挑出两组方程: xai(mod mi),xaj(mod mj)

我们把它转化为一般形式:x+yimi=ai,x+yjmj=am

也就是:aiaj=yimiyjmj

其中,只有yi,yj 是未知数,所以可以看做关于yi,yj的二元一次方程。

根据裴蜀定理,如果aiaj不能整除gcd(mi,mj),那么方程无解。

假设一组特解是yi=y1,yj=y2,那么通解就是:

yi=y1+kmjgcd(mi,mj),yj=y2kmigcd(mi,mj)

x 的特解是 x0=aiy1mi

x 的通解是

x=ai(y1+kmjgcd(mi,mj))mi

也就是 x=x0k×lcm(mi,mj)

也就是xx0(mod lcm(mi,mj))

这样,我们就把两个方程合并成了一个方程。不断合并下去,就能求出原方程组的解。

ll mul(ll a,ll b,ll mod){
	ll s=a;a=0;bool ok=0;
	if(b<0)
		b=-b,ok=1;
	while(b){
		if(b&1)
			a=(a+s)%mod;
		s=(s+s)%mod;b>>=1;
	}
	if(ok)
		a=-a;
	return a;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
	if(b==0){
		x=1;y=0;return a;
	}
	ll re=exgcd(b,a%b,x,y);
	ll tmp=x;x=y;y=tmp-y*(a/b);
	return re;
}
ll excrt(){
	ll y1=0,y2=0,x0=0,ans=0;
	for(int i=2;i<=n;++i){
		ans=exgcd(m[1],-m[i],y1,y2);
		ll lcm=m[1]/__gcd(m[1],m[i])*m[i];
		y1=mul(y1,m[1],lcm);
		x0=(a[1]-mul(y1,(a[1]-a[i])/ans,lcm)+lcm)%lcm;
		m[1]=lcm;a[1]=x0;
	}
	return x0;
}
int main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;++i)
		scanf("%lld%lld",&m[i],&a[i]);
	printf("%lld\n",excrt());
	return 0;
} 

posted @   andy_lz  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示