加载中…

返回上一页

数学知识

咕了好久没有公开,今天终于公开了……

矩阵

什么是矩阵?

其实就是一个二维数组.用你说

矩阵乘法

就是把两个矩阵乘起来,获得一个新的矩阵.

需要注意它只满足结合律,不满足交换律.

A 矩阵为 nm 列的矩阵,且 B 矩阵为 mp 列的矩阵(因为行数列数不相同是没有乘法一说的).

公式:

参考代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 101
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rll f=0,x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x;if(x>9) write(x/10);putchar(x%10|'0'); }
struct node// 封装版
{
	lla[201][201];
	node operator*(const node b)
	{
		node c;
		memset(c.a,0,sizeof(c.a));
		for(rll i=1;i<=n*10;i++)
			for(rll j=1;j<=n*10;j++)
				for(rll k=1;k<=n*10;k++)
					c.a[i][j]=(c.a[i][j]+a[i][k]*b.a[k][j])%mod;
		return c;
	}
}a;
ll a[maxn][maxn],b[maxn][maxn],c[maxn][maxn];
int main()
{
	n=read();m=read(); for(rll i=1;i<=n;i++) for(rll j=1;j<=m;j++) a[i][j]=read();
	p=read(); for(rll i=1;i<=m;i++) for(rll j=1;j<=p;j++) b[i][j]=read();
	for(rll i=1;i<=n;i++) for(rll j=1;j<=p;j++) for(rll k=1;k<=m;k++) c[i][j]+=a[i][k]*b[k][j];
	for(rll i=1;i<=n;i++)
	{
		for(rll j=1;j<=p;j++) write(c[i][j]),put_;
		putn;
	}
	return 0;
}

矩阵快速幂

利用快速幂的性质,可以将其推广到矩阵上.

点击查看代码
inline ll ksm(rg node a,rll t)
{
	rg node ans=a;
	for(rll i=t;i;i>>=1) { if(i&1) ans=ans*a;a=a*a; }
	return ans.a[1][n];
}

高斯消元

线性方程组

其实就是一堆一次方程组合到了一起.

高斯消元是把每一个线性方程组放到矩阵里,每一次进行消元.

系数矩阵:就是把方程的每一个系数提出来,放在对应的位置(例如 x1 的系数放在第 1 个位置,x2 的系数放在第 2 个位置).

增广矩阵:向系数矩阵后面加一列,表示每个方程等号右边的常数.

比如这个方程:

化为增广矩阵就是:

.

如何判断是否有解?

如果前面的方程加和后与后面的方程冲突(系数同常数项不同),那么一定无解. 废话

如果系数同常数项也同,那么该方程有多解.

其余情况只有一解.

怎么解

每次把一个未知数的系数消为 0,只剩下一个方程的这位系数不为 0.

具体来说:设当前消到了第 i 位,那么就把从第 i + 1 位开始所有的这一位进行代入,把它的系数消为 0.

这样一个方程组就被消成了个倒三角的形状.

(随便拉过来一张图作展示)

然后,就是……

从下往上把每一位消掉

下面是代码:

点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define ld double
#define rll rg ll
#define maxn 51
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rll f=0,x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x;if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,now=1;//now是现在消到了第几行
ld a[maxn][maxn];
int main()
{
	n=read(); for(rll i=1;i<=n;i++) for(rll j=1;j<=n+1;j++) a[i][j]=read();
	//第i+1列存的是等号后的数值
	for(rll l=1;l<=n;l++)//第几列
	{
		rll mx=now; for(rll i=now+1;i<=n;i++) if(abs(a[i][l])>abs(a[mx][l])) mx=i;
		if(!a[mx][l]) continue; for(rll i=1;i<=n+1;i++) swap(a[now][i],a[mx][i]);
		//把当前行和元系数最大的行交换
		for(rll i=1;i<=n;i++)//消元过程
		{
			if(i==now) continue; rg ld t=a[i][l]/a[now][l];//找到能消的最大系数
			for(rll j=l+1;j<=n+1;j++) a[i][j]-=a[now][j]*t;
		}
		now++;//所在行+1
	}
	if(now<n+1)//因为最后多加了个1
	{
		while(now<n+1) { if(a[now][n+1]) { puts("-1");return 0; } now++; }
		puts("0"); return 0;
	}
	for(rll i=1;i<=n;i++)
	{
		putchar('x');write(i);putchar('=');
		if(!(ll)(a[i][n+1]/a[i][i]*100)) puts("0.00");
		else printf("%.2lf\n",a[i][n+1]/a[i][i]);
	}
	return 0;
}

数论基础

素数

就是质数.

定义一个数是素数,当且仅当它是除 1 以外的正整数且它的因数只有 1 和它本身.

筛法求素数

埃氏筛

枚举每个 i,然后枚举它的倍数,将它们设为非素数. 对于后面是非素数的,就不再枚举了.

实现

点击查看代码
inline void shai()
{
	notp[1]=1;
	for(rll i=2;i<maxn;i++) if(!notp[i])
		for(rll j=2;i*j<maxn;j++) notp[i*j]=1;
}

线性筛

每个非素数由它的最小质因子筛掉.

实现

点击查看代码
ll prime[maxn],cnt;
bool notp[maxn];
inline void xxs()
{
	notp[1]=1;
	for(rll i=2;i<=n;i++)
	{
		if(notp[i]) prime[++cnt]=1;
		for(rll j=1;j<=cnt&&i*prime[j]<=n;j++)
		{
			notp[i*prime[j]]=1;
			if(!(i%prime[j])) break;// 每个合数只需要被筛一次
		}
	}
}

筛法求欧拉函数和莫比乌斯函数

下面有讲.

同余

顾名思义,就是当在同一个模数下两个数对于这个数取模后的结果是相同的.

记作:a ≡ b (mod m).

性质的话都很简单,先不说了.

逆元

乘法逆元常用来解决在模数意义下除法的问题.

一般用来求逆元的方法有两种:

  1. 费马小定理

它是借助乘法快速幂实现的.

当模数 p 为素数时,一个数在模其意义下的乘法逆元是这个数的模数减二次方.

由于是复习,具体证明就不再细说.

实现:

点击查看代码
inline ll ksm(rll a,rll b)
{
	rll ans=1; a%=mod;
	for(rll i=b;i;i>>=1)
	{
		if(i&1) ans=ans*a%mod; a=a*a%mod;
	}
	return ans;
}

ny=ksm(n,mod-2);
  1. 扩展欧几里得定理

求最大公约数

辗转相除法. 每次将 a 变为 b,然后使 b 变为 a % b. 其可用递归或者 while 循环实现.

点击查看代码
inline ll gcd(rll a,rll b) { if(!b) return a; return gcd(b,a%b); }

将其扩展一下:

我们知道,在模 p 意义下,一个数 a存在乘法逆元当且仅当 gcd(a , p) = 1.

这个定理常用来解方程 ax + by = gcd(a , b)xy 的整数解.

那么就有 ab 的乘法逆元,yba 的乘法逆元.

点击查看代码
inline ll exgcd(rll a,rll b,rll& x,rll& y)
{
	if(!b) { x=1; y=0; return a; }
	rll ans=exgcd(b,a%b,x,y),t=x; x=y;y=t-a/b*y;
	return ans;
}
// 求出来的x即为逆元

欧拉函数

欧拉函数指的是对于一个数 n,小于等于它的数中与它互质的数的个数.

公式

其中 pin 的所有质因数.

性质(搬的):

  1. φ(1)=1

  2. p 是一个素数,则 φ(p)=p−1

  3. p 是一个素数,则 φ(pk)=(p−1)×pk−1

  4. 欧拉函数为积性函数:对于任意两个正整数 a,b,且 gcd(a,b)=1,则 φ(a×b)=φ(a)×φ(b). 特别的,对于奇数 nφ(2n)=φ(n).

如何求欧拉函数

  1. 求单个数的欧拉函数

    在分解质因数的同时去求即可.

点击查看代码
inline ll phi(rll x)
{
	rll n=ceil(sqrt(x)),ans=x;
	for(rll i=2;i<=n;i++) if(!(x%i))
	{
		ans=ans/i*(i-1);
		while(!(x%i)) x/=i;
	}
	if(x>1) ans=ans/x*(x-1); return ans;
}
  1. 线性筛求多个数的欧拉函数
点击查看代码
ll phi[maxn];
inline void shai()
{
	for(rll i=1;i<maxn;i++) phi[i]=i;
	for(rll i=2;i<maxn;i++) if(phi[i]==i) for(rll j=i;j<maxn;j+=i) phi[j]=phi[j]*(i-1)/i;
}

排列组合

排列n 个数以不同的顺序出现在数列中.

n 个数中选择 m 个数进行有序排列,总共的方案数为 .

求总共排列数的方法:

.

组合n 个数无序地分在一起.

n 个数中选择 m 个数进行无序组合,总共的方案数为 .

求总共组合数的方法:

.

求排列组合数的实现:

点击查看代码
ll jc[maxn];
inline ll A(rll n,rll m)
{
	if(n<m) return 0;
	return jc[n]/jc[n-m];
}
inline ll C(rll n,rll m)
{
	if(n<m) return 0;
	return jc[n]/jc[m]/jc[n-m];
}

阶乘这玩意太大,需要取模. 把除换成快速幂即可.

点击查看代码
ll jc[maxn];
inline ll ksm(rll a,rll b)
{
	rll ans=1;a%=p;
	for(rll i=b;i;i>>=1)
	{
		if(i&1) ans=ans*a%p;
		a=a*a%p;
	}
	return ans;
}
inline ll A(rll n,rll m)
{
	if(n<m) return 0;
	return jc[n]*ksm(jc[n-m],p-2)%p;
}
inline ll C(rll n,rll m)
{
	if(n<m) return 0;
	return jc[n]*ksm(jc[m],p-2)%p*ksm(jc[n-m],p-2)%p;
}

Lucas 定理

内容

.

实现

点击查看代码
inline ll lucas(rll a,rll b)
{
	if(!b) return 1;
	return C(a%mod,b%mod)*lucas(a/mod,b/mod)%mod;
}

容斥原理

先扔个式子:

.
点击查看代码
$\left|\bigcup\limits_{i=1}^{n}S_i\right|=\sum\limits_{i=1}^{n}\left|S_i\right|-\sum\limits_{1\le i<j\le n}\left|S_i\cap S_j\right|+\sum\limits_{1\le i<j<k\le n}\left|S_i\cap S_j\cap S_k\right|+\cdots+\left(-1\right)^{n+1}\left|S_1\cap\cdots\cap S_n\right|$

举个例子很好理解:

假如我们要算 A ∪ B ∪ C,那么计算方法一定是 A + B + C - A ∩ B - A ∩ C - B ∩ C + A ∩ B ∩ C.

做题时经常用到.比如要计算 (x1 , y1)(x2 , y2) 的面积,那么就用 (x2 , y2) 的和减去 (x1 - 1 , y2) 减去 (x2 , y1 - 1),最后加上 (x1 - 1 , y1 - 1).

中国剩余定理(CRT)

它用来求解一个一元线性同余方程组.

例如如下方程组:

.

如何计算?

首先,计算所有模数的乘积,设它为 a

然后,对于第 i 个方程:

先计算出 m = ,然后计算 m 在模 ni 意义下的逆元,然后计算 ,方程的唯一解为 .

实现

点击查看代码
inline ll crt(ll n)//中国剩余定理
{
	rll t=1,ans=0;
	for(rll i=1;i<=n;i++) t*=b[i];
	for(rll i=1;i<=n;i++)
	{
		rll m=t/b[i],x,y;
		gcd(m,b[i],x,y);
		ans=(ans+a[i]*m*x%t)%t;
	}
	return (ans%t+t)%t;
}

BSGS

用来解高次同余方程 ax ≡ b (% p).

不是 noip 要求掌握的东西,懒得写了.

搬一个模板题的链接

posted @ 2022-10-05 16:15  1Liu  阅读(10)  评论(0)    收藏  举报