数学总结

主要整理一下 noip csp的数学

版权声明,大部分摘抄于《信息学奥赛之数学一本通》 如有侵权行为,本文作者将删除

持续更新ing

1.1辗转相除法

辗转相除法用来求两个数的最大公约数,又称欧几里得算法,其原理是:GCD(x,y)=GCD(x,y-x);

代码实现

int GCD(int x,int y){
    if(y==0) return x;
    else return GCD(y,x%y);
}

1.2最小公倍数LCM

定理:a,b两个数的最大公约数乘以它们的最小公倍数等于两数相乘

1.3扩展欧几里得算法

用来在已知(a,b)时,求解一组(p,q),使得p * a + q * b = GCD(a,b)

根据欧几里得算法可得,a和b都在减小,当b减小到0时,就可以得出p=1,q=0.然后递归回去就可以求出最终的p和q了。

代码实现

#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

int exgcd(int a,int b,int &x,int &y){//加上&会改变下方调用x,y的值 
	int ret,tmp;
	if(!b){
		x=1;
		y=0;
		return a;
	}
	ret=exgcd(b,a%b,x,y);
	tmp=x;
	x=y;
	y=tmp-a/b*y;
	return ret;
}

int main(){
	int a,b,x,y,z;
	cin>>a>>b;
	z=exgcd(a,b,x,y);//就是这里 
	cout<<z<<" "<<x<<" "<<y<<'\n';
	return 0;
}

1.4求解线性同余方程

定理1:对于方程a * x + b * y = c,该方程等价于a * c ≡ c (mod b),有整数解的充分必要条件是: c % GCD(a,b) = 0。

根据定理1,对于方程 a * x + b * y = c,我们可以先用扩展欧几里得算法求出一组x0,y0也就是 a * x0 + b * y0 = GCD(a,b),然后两边同时除以GCD(a,b),再乘以c。这样就得到了方程 

a * x0 * c / GCD(a,b) + b * y0 * c / GCD(a,b) = c,我们也就找到了方程的一个解。

定理2:若GCD(a,b)=1,且x0,y0,为a * x+ b * y = c的一组解,则该方程的任一解可表示为:x = x0 + b * t ,y = y0 - a * t,且对任一整数t,皆成立。

根据定理2,可以求出方程的所有解。但实际问题中,我们往往被要求去求最小整数解,也就是求一个特解x,t = b / GCD(a,b),x = (x % t + t) % t。

代码实现

int exgcd(int a,int b,int &x,int &y){
	if(b==0){
		x=1;
		y=0;
		return a;
	}
	int d=exgcd(b,a%b,x,y);
	int tmp=x;
	x=y;
	y=tmp-a/b*y;
	return d;
} //用扩展欧几里得算法求解线性方程 ax+by=c;

bool get(int a,int b,int c,int &x,int &y){
	int d=exgcd(a,b,x,y);
	if(c%d) return false;
	int k=c/d;
	x*=k;
	y*=k;
	//求的只是其中一个解 
	return true;
}

2.1逆元

若a * x ≡ 1(mod b),a,b互质,则称x为a的逆元,记为a^{-1}a1

当然在竞赛中有很多方法求解逆元,这里不再一一枚举,只重点总结两种常用的方法

求解方法1

前缀知识 费马小定理

a^{p-1}ap1 ≡ 1 (mod p)

至于证明。。。上网自行百度吧

我们发现根据逆元的定义可得

a^{p-2}ap2 * a^{}a ≡ 1 (mod p)

a^{p-2}ap2是a^{}a的逆元

我们可以用快速幂来求解这个问题

求解方法2

用了一种类似递推的方式

我就直接上代码了

因为我不会严格的证明但是代码很短可以直接背下来

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;

#define int long long

const int maxn=4000100;
int n,p;

int ans[maxn];

signed main(){
	cin>>n>>p;
	ans[1]=1;
	for(int i=2;i<=n;i++) ans[i]=(p-p/i)*ans[p%i]%p;
	for(int i=1;i<=n;i++) cout<<ans[i]<<'\n';
	return 0;
}

3.1中国剩余定理

设正整数两两互素,则同余方程组

有整数解。并且在模下的解是唯一的,解为

其中,而的逆元。

代码实现


int CRT(int a[],int m[],int n)
{
    int M = 1;
    int ans = 0;
    for(int i=1; i<=n; i++)
        M *= m[i];
    for(int i=1; i<=n; i++)
    {
        int x, y;
        int Mi = M / m[i];
        extend_Euclid(Mi, m[i], x, y);
        ans = (ans + Mi * x * a[i]) % M;
    }
    if(ans < 0) ans += M;
    return ans;
}

4.1卡特兰数

这部分建议去洛谷博客观看效果更佳

这是组合数学中一个经常出现在各种计数问题中的数列,其前几项为:1,2,5,14,42,132,429,1430,4862,16796......

求解卡特兰数的第n项,可以用一下几个公式

1.递推公式1

f(n) = \sum_{i=0}^{n-1}i=0n1 f(i)*f(n-i-1)

2.递推公式2

f(n)=\frac{f(n-1)*(4*n-2)}{n+1}n+1f(n1)(4n2)

3.组合公式1

f(n)=\frac{C^{n}_{2n}}{n+1}n+1C2nn

4.组合公式2

f(n)=C^{n}_{2n}C2nn-C^{n-1}_{2n}C2nn1

代码就自行百度吧。。。主要我也没写过。。。

posted @ 2019-10-09 20:03  真香警告  阅读(251)  评论(0)    收藏  举报