【基础总结】——数学知识

最大公约数与最小公倍数

理解起来挺简单的
重要等式: l c m [ a , b ] × g c d ( a , b ) = a × b lcm[a,b]\times gcd(a,b)=a\times b lcm[a,b]×gcd(a,b)=a×b
所以只要知道最大公约数就行。

int gcd(int a,int b)
{
	return b?gcd(b,a%b):a;
}

该代码运用了辗转相除法。因为 ( a , b ) = ( b , a 模 b ) (a,b)=(b,a模b) (a,b)=(b,ab),所以一直模模模模模模模模直到 b b b为0,那么此时的最大公约数就是 a a a,然后递归回去。

算数唯一分解定理

定义:任一大于1的整数n 能表示成质数的乘积,且其分解的结果是唯一的[不考虑次序].
直接上代码理解

void fenjie(int n)
{
	js=0;
	for(int i=2;i*i<=n;i++)
	{
		if(n%i==0) 
		{
			js++,p[js]=i,c[js]=0;
			while(n%i==0) n/=i,c[js]++;
		}
	}
	if(n>1) js++,p[js]=n,c[js]=1;
}

p p p是底数, c c c是指数
1.找n的因数,只要它能除下这个数,就一直除除除除除除除,直到除除不下,别忘了指数也要++。
2.这样一直循环,直到找完了n的所有因子,但是n可能是个质数,所以如果一直没有找到它的因子,那么他就只能分成 n 1 n^1 n1

线性筛找素数( N N N

用腻了之前简单的试除法,来看看这个线性筛吧

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

f [ i ] f[i] f[i]记录的是 i i i最小质因子,而 a n s [ i ] ans[i] ans[i]记录的是目前找到的质数
1.线性筛其实是基于埃氏筛的,所以简单说一下。之前我们找素数是每个都判断,但是一个数的倍数一定不是质数,所以埃氏筛在找到一个质数的时候了,把这些质数的倍数都标记了。
2.但是聪明的某某发现,这样子会有大量重复标记,比如30会被2,3,5,标记,所以他想到用一个数的最小质因子来标记,这样每个数就只被标记了一次。
3.可以来简单证明一下,如果不用最小质因子标记,那么30可能会被 3 × 10 3\times 10 3×10标记,但是10能分成 2 × 5 2\times 5 2×5,所以此时30一定被标记了两次。
4.对应代码倒数第二行,当质数表里的数大于了这个数的最小质因子,那么就 b r e a k break break,并且,如果这个数标记的数超过 n n n了,也不用管了.

扩展欧几里得

裴蜀定理:
a x + b y = c ax+by=c ax+by=c方程有解时当且仅当 c c c g c d ( a , b ) gcd(a,b) gcd(a,b)的倍数(若 a , b a,b a,b互素,则 a x + b y = 1 ax+by=1 ax+by=1有解)

欧几里得算法的核心是把 ( a , b ) (a,b) (a,b)辗转为 ( b , a % b ) (b,a \%b) (b,a%b),假设 ( b , a % b ) (b,a\%b) (b,a%b)存在对应的 ( x 1 , y 1 ) (x1,y1) (x1,y1)使得 b × x 1 + ( a % b ) × y 1 = c b\times x1+(a\%b)\times y1=c b×x1+(a%b)×y1=c
根据: a x + b y = b × x 1 + ( a % b ) × y 1 = b × x 1 + ( a − [ a / b ] × b ) × y 1 = a × y 1 + b × ( x 1 − [ a / b ] × y 1 ) ax+by=b\times x1+(a\%b)\times y1=b\times x1+(a-[a/b]\times b)\times y1=a\times y1+b\times (x1-[a/b]\times y1) ax+by=b×x1+(a%b)×y1=b×x1+(a[a/b]×b)×y1=a×y1+b×(x1[a/b]×y1)
x = y 1 , y = x 1 − [ a / b ] × y 1 x=y1,y=x1-[a/b]\times y1 x=y1,y=x1[a/b]×y1
所以,基于这样的操作,我们的递归代码就产生了~

int work(int a,int b,int &x,int &y)
{
	if(b==0) {x=1,y=0;return a;}
	int d=work(b,a%b,x,y);
	int z=x;x=y,y=z-a/b*y;
	return d;
}

此时的 x , y x,y x,y就是该方程的一组特解了。
有了特解,我们就可以求通解了。
该公式为: x = x 0 × ( c / d ) + k × ( b / d ) , y = y 0 × ( c / d ) − k × ( a / d ) x=x_0\times (c/d)+k\times (b/d),y=y_0\times (c/d)-k\times (a/d) x=x0×(c/d)+k×(b/d),y=y0×(c/d)k×(a/d)
注意这里符号是一加一减,具体证明…你不需要知道【滑稽】其实是我不会
经典例题:
天平称重

容斥原理

这个和数学鲍姐讲的一样,不多说了,感觉这道题的思想很像容斥 codeforces,C题

欧拉函数

定义:

对正整数n,欧拉函数是小于或等于n的数中与n互质的数的数目。

性质:

(1) φ ( 1 ) = 1 φ(1)=1 φ(1)=1
(2) φ ( p ) = p − 1 φ(p)=p-1 φ(p)=p1
(3) φ ( p k ) = p k − p k − 1 = ( p − 1 ) p k − 1 φ(p^k)=p^k-p^{k-1}=(p-1)p^{k-1} φ(pk)=pkpk1=(p1)pk1
(4)欧拉函数是积性函数——若m,n互质,则 φ ( m n ) = φ ( m ) φ ( n ) φ(mn)=φ(m)φ(n) φ(mn)=φ(m)φ(n)。(若函数是完全积性函数,则不需要互质条件)
(5)对于任意 n = p 1 k 1 × p 2 k 2 × . . . × p r k r n=p_1^{k_1}\times p_2^{k_2}\times ...\times p_r^{k_r} n=p1k1×p2k2×...×prkr (其中 p 1 , p 2 , . . . , p k p_1,p_2,...,p_k p1,p2,...,pk n n n 的互不相同的质因子) 则有 φ ( n ) = ∏ i = 1 r φ ( p i k i ) = ∏ i = 1 r ( p i − 1 ) p i k i − 1 = ∏ i = 1 r ( 1 − 1 p i ) × p i k i = n × ∏ i = 1 r ( 1 − 1 p i ) \varphi(n)=\prod_{i=1}^{r}\varphi(p_i^{k_i})=\prod_{i=1}^{r}(p_i-1)p_i^{k_i-1}=\prod_{i=1}^{r}(1-\frac 1{p_i})\times p_i^{k_i}=n\times \prod_{i=1}^{r}(1-\frac 1{p_i}) φ(n)=i=1rφ(piki)=i=1r(pi1)piki1=i=1r(1pi1)×piki=n×i=1r(1pi1)

这第五条性质简直太妙了,于是我们就可以用这个去求欧拉函数了( N \sqrt N N

long long oula(int x)
{
	ans=x;
	for(int i=2;i<=sqrt(x);i++)
	{
		if(x%i==0) 
		{
			ans=ans/i*(i-1);//这里用到了
			while(x%i==0) x/=i;
		}
	}
	if(x>1) ans=ans/x*(x-1);//防止n为质数
	return ans;
}

这个模板有没有很眼熟?没错,和埃氏筛很像,也就是说可以边筛素数边求欧拉函数,双倍的快乐【滑稽】
当然,更快的还是线性筛( N N N)

void oula(int x)
{
	for(int i=2;i<=x;i++)
	{
		if(!f[i]) p[++cnt]=i,F[i]=i-1;
		for(int j=1;j<=cnt&&i*p[j]<=x;j++)
		{	
			f[i*p[j]]=1;
			if(i%p[j]==0) {F[i*p[j]]=F[i]*(p[j]);break;}
			else F[i*p[j]]=F[i]*(p[j]-1);
		}
	}
}

这样就成功起飞了【芜湖】

逆元

定义什么的只可意会不可言传,主要用法就是在除一个数的时候,要求取模,那么就可以用$\times $他的逆元来代替。

对于逆元的求解方法才是我们应该掌握的
1.拓展欧几里得(适用于a,b互质的情况下,代码太麻烦,不常用)
依然是上面给出的代码, x x x即为所求的逆元
2.费马小定理(好写,不出错, l o g N logN logN a p − 1 ≡ 1 ( % p ) a^{p-1}\equiv 1(\%p) ap11(%p)
同时 / a /a /a就能得到 a p − 2 ≡ a − 1 ( % p ) a^{p-2}\equiv a^{-1}(\%p) ap2a1(%p)
这样通过快速幂就能求出逆元了(大爱这种方法,但是多次询问时可能超时)

欧拉定理

若n,a为正整数,且n,a互质,即gcd(n,a)=1,则 a φ ( n ) ≡ 1 ( % p ) a^{φ(n)}\equiv 1(\%p) aφ(n)1(%p)
可以看出,费马小定理是欧拉函数的一种特殊情况
一些比较恶心的推论:

a b ≡ a b % φ ( n ) % n a^b\equiv a^{b\%φ(n)} \%n abab%φ(n)%n
a , n a,n a,n不一定互质时, a b ≡ a b % φ ( n ) ( % n ) a^b\equiv a^{b\%φ(n)} (\%n) abab%φ(n)(%n)

中国剩余定理

韩信点兵大家都知道,这个就是解决类似的问题,只不过更快【滑稽】,但是也更麻烦。


【例题】存在一个数x,除以3余2,除以5余3,除以7余2,然后求这个数
首先假如我们求出这样三个数k1,k2,k3,满足k1与3互质且是5和7的倍数,k2与5互质且是3和7的倍数,k3与7互质且是3和5的倍数,那么容易意会得到, k 1 × 2 + k 2 × 3 + k 3 × 2 k1\times 2+k2\times 3+k3\times 2 k1×2+k2×3+k3×2一定会是一个满足题
目条件的数。而题目的通解可表示为这个数每次都加上3,5,7的最小公倍数
首先我们求出3,5,7的lcm=105

然后我们令:

x 1 = 105 / 3 = 35 x1=105/3=35 x1=105/3=35, x 2 = 105 / 5 = 21 x2=105/5=21 x2=105/5=21, x 3 = 105 / 7 = 15 x3=105/7=15 x3=105/7=15

然后我们求解以下方程: ( ( a × x 1 ) (a\times x_1) (a×x1)就是 k 1 k_1 k1

a × x 1 % 3 = 1 a\times x1\%3=1 a×x1%3=1, b × x 2 % 5 = 1 b\times x2\%5=1 b×x2%5=1, c × x 3 % 7 = 1 c\times x3\%7=1 c×x3%7=1

这个格式的式子好眼熟,用扩展欧几里德求a=2,b=1,c=1。

答案就是:

a n s = ( a × x 1 × 2 + b × x 2 × 3 + c × x 3 × 2 ) % l c m = 23 ans=(a\times x1\times 2+b\times x2\times 3+c\times x3\times 2)\%lcm=23 ans=(a×x1×2+b×x2×3+c×x3×2)%lcm=23


通过以上例题,我们可以总结出求解的基本步骤

1.求出除数的乘积(不是最小公倍数没关系,这样方便)
2.循环,每次用公倍数除以除数,把得到的数当做 a a a,将除数当做 b b b
3.运用扩展欧几里得求解出x, a n s ans ans加上 a × x × 余 数 a\times x\times 余数 a×x×,然后再模公倍数

那么来看看代码吧

for(int i=1;i<=n;i++)
{
	long long x,y;
	long long aa=sum/a[i];
	ojld(aa,a[i],x,y);
	ans=(x*aa%sum*b[i]%sum+ans)%sum;
}

高斯消元( n 3 n^3 n3

上三角五步走:

int t=r;
for(int i=r;i<=n;i++) if(fabs(a[i][c])>fabs(a[t][c])) t=i;//找当前这一列绝对值最大的数 
if(fabs(a[t][c])<py) continue;//如果这列全是零了,就不管 
for(int i=c;i<=n+1;i++) swap(a[t][i],a[r][i]);//把他换到没被锁定的第一行 
for(int i=n+1;i>=c;i--) a[r][i]/=a[r][c];//把这个数变成1,为了维护等式这一行都要除这个数 
for(int i=r+1;i<=n;i++) if(fabs(a[i][c])>py) for(int j=n+1;j>=c;j--) a[i][j]-=a[r][j]*a[i][c];
//把每行的第c个数都消为0 
//第二层循环倒着写,因为如果先把第一个变成0了,那后面的运算都要依靠第一个值,会出错 
r++;

线性基

简单来说是一些数的集合,而这些数通过异或可以构成的数都不在这个集合中。毕竟是“基”,基础嘛,肯定是最最最最最下面的东西,没有更小的了,也就是没有数通过变换能构成他们
有关更详细 的介绍和一些经典代码的写法,参见
点我点我(作者:Hypoc_)

卡特兰数(设为h(n))

  1. 通项公式: h ( n ) = 1 / ( n + 1 ) × C 2 n n h(n)=1/(n+1)\times C^n_{2n} h(n)=1/(n+1)×C2nn
  2. 递推式子: h ( n + 1 ) = ( 4 n + 2 ) / ( n + 2 ) × h ( n ) h(n+1)=(4n+2)/(n+2)\times h(n) h(n+1)=(4n+2)/(n+2)×h(n)

FWT

简单来说看下图

在这里插入图片描述

行列式

性质

  1. 交换对应矩阵的 2 行(列),行列式取反
  2. 交换 1 行与 1 列(进行一次矩阵转置),行列式不变
  3. 行列式的行(列)所有元素等比例变化,则行列式也等比例变化
  4. 如果行列式对应矩阵 A 中有一行(列),是对应 2 个矩阵 B,C 中分别的 2 行(列)所有元素之和。那么有 A=B+C
  5. 如果一个矩阵存在两行(列)成比例则 A的值=0
  6. 把一个矩阵的一行(列)的值全部乘一个常数加到另一行(列)上,行列式值不变

求值

初始为 ∣ 2 5 ∣ |\frac{2}{5}| 52
使第二行除以(5/2) ∣ 2 1 ∣ |\frac{2}{1}| 12
交换这两行 ∣ 1 2 ∣ |\frac{1}{2}| 21
第二行减第一行的两倍 ∣ 1 0 ∣ |\frac{1}{0}| 01
交换 ∣ 0 1 ∣ |\frac{0}{1}| 10
一直做下去就好啦

int work()
{
	int w=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=i+1;j<=n;j++)
		{
			while(a[i][i])
			{
				int tmp=a[j][i]/a[i][i];
				for(int k=i;k<=n;k++) a[j][k]=((a[j][k]-1ll*tmp*a[i][k])%p+p)%p;
				swap(a[i],a[j]),w=-w;
			}
			swap(a[i],a[j]),w=-w;
		} 
	}
	for(int i=1;i<=n;i++) w=1ll*w*a[i][i]%p;
	return (w%p+p)%p;
}

矩阵求逆

我们现在要求 A A A的逆矩阵 A − 1 A^{-1} A1
E E E为单位矩阵,也就是对角线上的数都是1,其他是0
那么根据定义 A × A − 1 = E , E × A − 1 = A − 1 A\times A^{-1}=E,E\times A^{-1}=A^{-1} A×A1=E,E×A1=A1
所以我们将 A A A变成 E E E的过程中,对另一个 E E E也做同样的操作(这两个 E E E肯定不同呀),于是后面的那个 E E E就被我们变成 A − 1 A^{-1} A1

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值