数论小集(1)

话说当初我不选择数学竞赛与其他竞赛的原因,就是我以为信息学竞赛有关数学的方面不怎么较难。结果到数论时,我就GG了,所以这次借着复习,巩固数论。

(注:本文以实用和总结为主,大部分定理与公式是没有证明的)

数论小集(基础篇)

1.质数

既然质数的英文名叫做“Prime number”,而Prime又有“基础的”的意思,那么它是很重要的。
判断一个数是不是质数可以用O(sqrt(n))的复杂度(枚举1~sqrt(n)的数 ),但是若要求1~n的质数,则可以用欧拉筛以O(n)的算法求出。代码:
void Prime(int n)//
{
	cnt=0;//cnt从零开始 
	memset(vis,0,sizeof(vis));
	for(int i=2;i<n;i++)
	{
		if(!vis[i])
		prime[cnt++]=i;
		for(int j=0;j<cnt&&i*prime[j]<n;j++)//prime数组从零开始 
		{
			vis[i*prime[j]]=1;
			if(i%prime[j]==0)
			break;
		}
	}
	return ; 
}
其实还可以用这个来求每个数的最小质因子,稍作修改即可(推荐:BZOJ3233)
void Prime(int num)
{
	cnt=0;
	memset(minn,0,sizeof(minn));
	for(int i=2;i<=num;i++)
	{
		if(!minn[i])
		{
			prime[cnt++]=i;
			minn[i]=i;
		}
		for(int j=0;j<cnt&&i*prime[j]<=num;j++)
		{
			minn[i*prime[j]]=prime[j];
			if(i%prime[j]==0) break;
		}
	}
}

2.gcd与lcm

gcd是最大公因数,lcm是最小公倍数。
gcd用辗转相除法,复杂度为O(logn)的,而lcm则建立在gcd之上:lcm(a,b)=a/gcd(a,b)*b
代码:
int gcd(int a,int b)//最大公约数 
{
	return b==0?a:gcd(b,a%b);
}
int lcm(int a,int b)//最小公倍数 
{
	return a/gcd(a,b)*b;//注意:这里应该先除后乘,减少溢出的可能
}

3.模运算基础

有:
(a+b)%mod=((a%mod)+(b%mod ))%mod
(a*b)%mod=((a%mod)*(b%mod))%mod
(a-b)%mod=((a%mod)-(b%mod)+mod)%mod
以及快速幂(O(logn))取模:
int pow(int base,int b)//建议使用循环,而不用递归(容易崩栈!血的教训!)
{
    int res=1;
    while(b)
   {
       if(b&1) res=res*base%mod;
       base=base*base%mod;
       b>>=1;
    }
    return res;
}

4.(重点)扩展欧几里得算法

扩展欧几里得能够找出一对(x,y),使得ax+by=gdc(a,b),并有以下简易结论:
结论1: 若方程ax+by=c的一组整数解为(x0,y0),则它的任意整数解都可以写成(x0+kb',y0-ka'),其中a'=a/gcd(a,b),b'=b/gcd(a,b),k取任意整数。 
结论2: g=gcd(a,b),方程ax+by=g的一组解是(x0,y0),则当c是g的倍数时ax+by=c的一组解是(x0*c/g,y0*c/g);否则无解。
它的作用很多,以后应该会讲到,其中最基本的就是他可以解两元一次方程组(利用以上两个结论)。
代码:
void gcd(int a,int b,int g,int &x,int &y)
{
    if(!b) {g=a;x=1;y=0;}
    else {gcd(b,a%b,g,y,x);y-=x*(a/b);}
}
5.计数问题
基础的加法原理,乘法原理,以及容斥原理应该都很简单(很多dp都会用)
主要是C(n,m),其实P(n,m)都用得很少。
关于C(n,m)简单的有以下几种算法
void C(int n,int m)
{
	/*1.*/for(int i=1;i<=n;i++)
	{
		f[i][i]=f[i][0]=1;
		for(int j=1;j<=i;j++)
	 	{
	 		f[i][j]=f[i-1][j]+f[i-1][j-1];//排列数的递推公式
	 	}
	}//递推式
	/*2.*/f[n][m]=n!/m!(n-m)!//公式,可以预处理阶乘,但由于要用除法,n和m太大后要溢出,
                                 //取模又没有除法运算(但有逆元),总之就是比较蛋疼的算法
        /*3.*/c[0]=1;利用C(n,k)=(n+1-k)/k*C(n,k-1)
	for(int i=1;i<=n;i++)c[i]=c[i-1]*(n-i+1)/i;实际意义不明显,但。。。很好玩
}                 

以上就是一部分笔者觉得重要的基础,虽然应用感觉很少,但是接下来大多数都建立在这些之上,至少把代码记住还是很重要的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值