简单数论合集

数论

gcd

这个就很简答了,直接看代码

int gcd(int x,int y){
return !y?x:gcd(y,x%y);
}

gcd也有一点点的性质
在这里插入图片描述
主要还是 结合律 比较有用

还有就是这个算法的复杂度合适最大呢,其实就是去求 斐波那契数列 的相邻两项的gcd,这也是一个比较神奇的性质

太简单了,所以来一个难一点的

exgcd

这个可以干啥呢

ax+by=n.
在这里插入图片描述

之后就是代码

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

当然这个也可以求 ax≡b(modn) 的解

只用求 ax+ny=b 的一组特殊解,之后转化为最小正解就好了

这个只适用于b可以整除gcd(a,n)的情况

这个也给我们提供了线性同余方程的转化方法
在这里插入图片描述

其实主要还是要去理解题目的转化引导

费马小定理

在这里插入图片描述

哪这个有啥用。

首先可以判断一个数是不是质数,只用随便去找一个a,之后看a的p-1次方mod p是不是等于1

还有啥用,就是求乘法逆元
在这里插入图片描述
这里的x就是我们要找的乘法逆元,最后只用快速幂加速一下就OK了,
但是只适用于p的质数的情况

int n,q;

ll fast(int b,int p){
	ll ans=1;
	b%=q;
	while(p){
		if(p%2==1) {
			ans*=b;
			ans%=q;
		}
		b=b*b%q;
	 	p/=2;
	}
	return ans;
}

int main(){
	scanf("%d%d",&n,&q);
	printf("1\n");
	for(int i=2;i<=n;i++){
		//cout<<i<<" ";
		printf("%lld\n",fast(i,q-2)); 
		
	}
		
	
	return 0;
}

中国剩余定理

这个就是韩信点兵的原理

这个是用来求解什么的呢
在这里插入图片描述

这个的证明是什么呢,其实也不是很难、
在这里插入图片描述

线性筛素数

这个其实就是** 希望每一个和数都被他的最小质因数给筛掉** 所以就可以达到线性的程度

至于原理其实我不是很懂,但是用处也不是很大所以就去理解一下这个代码

bool yuan[maxn];//判断是不是素数
int su[maxn];//存每一个素数
int cnt=0;

void shai(int x){
	memset(yuan,1,sizeof(yuan));
	yuan[1]=0;
	for(int i=2;i<=n;i++){
		if(yuan[i])su[++cnt]=i;
		for(int j=1;j<=cnt&&i*su[j]<=n;j++){
			yuan[su[j]*i]=0;
			if(i*su[j]==0) break;//核心代码	
		}
	}
	return;	
}

裴蜀定理

这个是啥呢,其实就是说
在这里插入图片描述

卢卡斯定理

这个是用来快速求解组合数取模的值的

主要的实现是需要乘法逆元,组合数计算的辅助

具体内容看图
在这里插入图片描述

代码实现

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll p,t,n,m;

long long fast(ll b,ll pp){
	long long ans=1;
	while(pp){
		if(pp%2==1) ans=ans*b%p;
		b=b*b%p;
		pp/=2;
	}
	return ans;
	
}

long long C(ll n,ll m){//n个数取m个的组合数,即c n,m 
	ll son=1,mum=1;//分子和分母 
	if(n<m) return 0;
	if(m>n-m) m=n-m;
	for(int i=0;i<m;i++){
		son=(son*(n-i))%p;
		mum=(mum*(i+1))%p;
	}// son从n乘到(n-m+1)mum从1乘到m 
//	cout<<mum<<"  "<<son<<endl;
	return son*fast(mum,p-2)%p;
}

ll lucas(ll n,ll m){//n个数中取出m个 
	if(m==0) return 1;
	return lucas(n/p,m/p)*C(n%p,m%p)%p;
}
	
int main(){
	scanf("%lld",&t);
	while(t--){
		scanf("%lld%lld%lld",&n,&m,&p);
		printf("%lld\n",lucas(n+m,m));
	}
	
	return 0;
}

推式子

整除分块

莫比乌斯反演

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值