文章目录
没错还有不到一个礼拜就要NOIP了,而我还在办公室敲代码(然而不觉得有什么用),而且NOIP后一个礼拜,还有大联考,真是完蛋。
但是,我还是要怀着悲痛的心情(刚在文化课上被班里巨神吊打)来整理一下NOIP中数学相关的知识点(毕竟在这方面挂过)。
1、最大公因数
这很基础了,辗转相除。
还是给一道例题吧:NOIP2009Hankson的趣味题
不多说,上代码:
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
2、最小公倍数
基础性质:lcm(a,b)=a*b/gcd(a,b)
借用gcd就好了。
代码如下:
int lcm(int a,int b){
return a*b/gcd(a,b);
}
这里提供一道例题:Hankson的趣味题
3、扩展欧几里得算法
本义是用来求解ax+by=gcd(a,b)的一组解的。
代码如下:
void exgcd(int a,int b,int& d,int& x,int& y){
if(b==0){
d=a;
x=1;
y=0;
}else{
exgcd(b,a%b,d,y,x);
y-=x*(a/b);
}
}
它有很多其他用处,一是解不定方程,或者是求逆元。
我们来看看逆元的求解方法。
其实逆元是不定方程的一种特殊形式,所以可以用扩欧来解决。
代码如下:
int inv(int a,int n){
int d,x,y;
exgcd(a,n,d,x,y);
return d==1?(x+n)%n:-1;
}
4、欧拉函数
欧拉函数(记作euler(i)),是指对于正整数i,小于等于它的正整数中,与i互质的数字的个数。
所以这也就引出了欧拉函数的计算公式:
euler(i)=i*(1-1/p1)*(1-1/p2)*…(1-1/pn)
其中p1到pn为i的质因数。
所以我们就会有一个非常朴素的算法:
int euler(int n){ //返回euler(n)
int res=n,a=n;
for(int i=2;i*i<=a;i++){
if(a%i==0){
res=res/i*(i-1);//先进行除法是为了防止中间数据的溢出
while(a%i==0) a/=i;
}
}
if(a>1) res=res/a*(a-1);
return res;
}
但是看到质因数,大家可能会想起素数筛法,所以欧拉函数也可以用筛法来求,代码如下:
void Init(){
euler[1]=1;
for(int i=2;i<Max;i++){
euler[i]=i;
}
for(int i=2;i<Max;i++){
if(euler[i]==i){
for(int j=i;j<Max;j+=i){
euler[j]=euler[j]/i*(i-1);//先进行除法是为了防止中间数据的溢出
}
}
}
}
这里给出一个例题:仪仗队(SDOI2008)
5、费马小定理
费马小定理是什么呢?
aφ(m)≡1(mod m) ((a,m)=1) (φ()为欧拉函数)
没什么对应的代码,但是却很有用。
首先它可以用来求逆元。这个放在逆元里说。
还有就是有一道例题:苦恼的小明
这道题就是用费马小定理来解决的。
6、快速幂
好像和数学没什么关系,和倍增倒像是亲家。但是毕竟涉及幂的知识,就放在这里。
这里提供一道例题:NOIP转圈游戏
代码如下:
long long fpow(long long x, long long n){
long long res=1;
while(n>0){
if(n&1)res=res*x;
x*=x;
n>>=1;
}
return res;
}
7、逆元
何谓逆元?若a*x=1(mod p),则在模p意义下,a和x互为逆元。
那么逆元有什么实际应用?
最常用的是取模。
因为,通常,为了防止中间数据溢出,我们会在计算的中途取模,这对于加和乘没有什么影响,但是对于除,就不成立了。所以我们需要变除为乘。这就用到逆元了,即在模p意义下,除以a等价于乘上x,这样就可以快乐地取模了。
除了用扩欧来求,我们还可以用费马小定理来求,代码如下(注意上面的汉字):
//费马小定理(mod为素数时,n为mod-2;mod为合数时,n为phi(mod)-1)
long long pow_mod(long long x, long long n, long long mod){
long long res=1;
while(n>0){
if(n&1)res=res*x%mod;
x=x*x%mod;
n>>=1;
}
return res;
}
一道逆元的模板题:同余方程(NOIP2012)
8、素数
素数判定
这个我们可以用朴素的判断方法:
int isprime(int a){
for(int i=2;i*i<=a;i++){
if(a%i==0){
return 0;
}
}
return 1;
}
素数筛法
很经典,不说了。
void findprime(int n){
int vis[n+1];
memset(vis,0,sizeof(vis));
for(int i=2;i<=n;i++){
if(vis[i]==0){
for(int j=i*i;j<=n;j+=i){
vis[j]=1;
}
}
}
}
9、杨辉三角
这个大家应该都知道。
这里只是罗列一道题目:NOIP2016组合数问题
10、Lucas定理
这个定理用于求较大的组合数。
因为较大的组合数,我们是没办法用杨辉三角递推的,也没办法直接用公式来求,毕竟你还要求逆元,会很麻烦。
所以我们需要Lucas定理,那么这个定理的内容是什么呢?
Lucas(n,m,p)=C(n%p,m%p)*Lucas(n/p,m/p,p)
其中Lucas(n,m,p)表示C(n,m)%p的结果,而C(n,m)表示组合数
有了这个公式,我们就可以快乐地递归了!
代码我不直接给了,你们可以看看这道例题:Perm
11、素数分解
我们都知道欧几里得老先生在《几何原本》中提出过唯一分解定理。
这里是唯一分解定理的一个简单应用。
就是把一个数分解成若干个素数的乘积。
代码非常简单,我就直接给代码了。
代码如下:
void div(){
memset(prime,0,sizeof(prime));
for(int i=2;i<=m1;i++){
while(m1%i==0){
prime[i]++;
m1/=i; maxu=i;
}
prime[i]*=m2;
}
}
---------------------
作者:cggwz
来源:CSDN
原文:https://blog.csdn.net/cggwz/article/details/83153153
版权声明:本文为博主原创文章,转载请附上博文链接!
我们顺便给一道例题:细胞分裂
12、基本知识和数学推导
我这里什么也不想放,你们就自己翻翻数学课本就好了。
比如计算几何,你就看看解析几何和向量,解三角形。
函数的话,你就看看基本初等函数和导数。
还有数学推导,这个亘古不变的能力要求,在考场上更多的还要靠这个。
这里提供若干个例题:
计算几何:Car的旅行路线
数学推导:密码
螺旋矩阵
火柴排队
观赏题:余数求和