高斯消元法
高 斯 消 元 法 可 以 在 O ( n 3 ) 的 时 间 复 杂 度 下 求 解 多 元 线 性 方 程 组 高斯消元法可以在O(n^{3})的时间复杂度下求解多元线性方程组 高斯消元法可以在O(n3)的时间复杂度下求解多元线性方程组
a 11 x 1 + a 12 x 2 + . . . + a 1 n x n = b 1 a 11 x 1 + a 12 x 2 + . . . + a 1 n x n = b 2 . . . . a n 1 x 1 + a n 2 x 2 + . . . + a n n x n = b n a_{11}x_{1}+a_{12}x_{2}+...+a_{1n}x_{n}=b_{1}\\ a_{11}x_{1}+a_{12}x_{2}+...+a_{1n}x_{n}=b_{2}\\ ....\\ a_{n1}x_{1}+a_{n2}x_{2}+...+a_{nn}x_{n}=b_{n} a11x1+a12x2+...+a1nxn=b1a11x1+a12x2+...+a1nxn=b2....an1x1+an2x2+...+annxn=bn
解一共有三种情况:
1.
无
解
2.
无
穷
解
3.
有
唯
一
解
1.无解\\ 2.无穷解\\ 3.有唯一解\\
1.无解2.无穷解3.有唯一解
可以通过其增广矩阵来解方程组:
[
a
11
a
12
.
.
.
a
1
n
a
21
a
22
.
.
.
a
2
n
.
.
.
a
n
1
a
n
2
.
.
.
a
n
n
b
1
b
2
.
.
.
b
n
]
\left [ \begin{array}{c:c} \begin{matrix} a_{11}&a_{12}&...a_{1n}\\ a_{21}&a_{22}&...a_{2n}\\ ...\\ a_{n1}&a_{n2}&...a_{nn}\\ \end{matrix}& \begin{matrix} b_{1}\\ b_{2}\\ ...\\ b_{n}\\ \end{matrix} \end{array} \right ]
⎣⎢⎢⎡a11a21...an1a12a22an2...a1n...a2n...annb1b2...bn⎦⎥⎥⎤
通过初等变换转换为上三角的形式:
a
11
x
1
+
a
12
x
2
+
.
.
.
+
a
1
n
x
n
=
b
1
a
12
x
2
+
.
.
.
+
a
1
n
x
n
=
b
2
.
.
.
.
a
n
n
x
n
=
b
n
a_{11}x_{1}+a_{12}x_{2}+...+a_{1n}x_{n}=b_{1}\\ a_{12}x_{2}+...+a_{1n}x_{n}=b_{2}\\ ....\\ a_{nn}x_{n}=b_{n}
a11x1+a12x2+...+a1nxn=b1a12x2+...+a1nxn=b2....annxn=bn
对应增广矩阵为;
[
a
11
a
12
.
.
.
a
1
n
0
a
22
.
.
.
a
2
n
.
.
.
0
0
.
.
.
a
n
n
b
1
b
2
.
.
.
b
n
]
\left [ \begin{array}{c:c} \begin{matrix} a_{11}&a_{12}&...a_{1n}\\ 0&a_{22}&...a_{2n}\\ ...\\ 0&0&...a_{nn}\\ \end{matrix}& \begin{matrix} b_{1}\\ b_{2}\\ ...\\ b_{n}\\ \end{matrix} \end{array} \right ]
⎣⎢⎢⎡a110...0a12a220...a1n...a2n...annb1b2...bn⎦⎥⎥⎤
高斯消元思路
枚举每一列:
- 找到绝对值最大的一行
- 将这一行换到最上面去
- 将该行的第c个数变成1
- 用第一行将下面所有行的第c列消成0
int gauss(){
int c,r;
for(c=1,r=1;c<=n;c++){
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])<eps) continue;
for(int i=c;i<=n+1;i++) swap(a[r][i],a[t][i]);
//第三步,逐列单位化
for(int i=n+1;i>=c;i--) a[r][i]/=a[r][c];
//逐行减去
for(int i=r+1;i<=n;i++)
if(fabs(a[i][c])>eps)
for(int j=n+1;j>=c;j--)
a[i][j]-=a[i][c]*a[r][j];
r++;
}
if(r<=n){
for(int i=r;i<=n;i++) //遍历每一行
if(fabs(a[i][n+1])>eps) return 2;
return 1;
}
for(int i=n-1;i>=1;i--) //从最后一行开始
for(int j=i+1;j<=n;j++) //从下一行开始
a[i][n+1]-=a[j][n+1]*a[i][j];
return 0;
}
组合数
定义法:
C a b = a ! b ! ⋅ ( a − b ) ! C_{a}^{b}=\frac{a!}{b! \cdot (a-b)!} Cab=b!⋅(a−b)!a!
迭代公式法:
C a b = C a − 1 b + C a − 1 b − 1 C_{a}^{b}=C_{a-1}^{b}+C_{a-1}^{b-1} Cab=Ca−1b+Ca−1b−1
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define MAXN 2010
const int mod=1e9+7;
using namespace std;
int C[MAXN][MAXN];
int a,b,n;
int main(){
for(int i=0;i<MAXN;i++)
C[i][0]=C[i][i]=1,C[i][1]=i;
//递推求解组合数
for(int i=1;i<MAXN;i++)
for(int j=1;j<i;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
scanf("%d",&n);
while(n--){
scanf("%d%d",&a,&b);
printf("%d\n",C[a][b]);
}
return 0;
}
卢卡斯定理:
C a b ≡ C a m o d p b m o d p ⋅ C a p b p ( m o d p ) C_{a}^{b} \equiv C_{a\ mod \ p}^{b\ mod \ p} \cdot \ C_{\frac{a}{p}}^{\frac{b}{p}} (mod\ p) Cab≡Ca mod pb mod p⋅ Cpapb(mod p)
int lucas(ll a,ll b){
if(a<p&&b<p) return C(a,b);
int res= (ll)C(a%p,b%p)*lucas(a/p,b/p)%p;
return res;
}
//C(a,b)即以a为底取b的组合数
组合数高精度
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define MAXN 5010
using namespace std;
bool numlist[MAXN];
int prime[MAXN],cnt=0,num[MAXN];
int a,b;
vector<int> res;
//欧拉筛筛出所有质数
void Eular(){
for(int i=2;i<=5001;i++){
if(numlist[i]==0){
prime[++cnt]=i;
}
for(int j=1;j<=cnt&&prime[j]<=5001/i;j++){
numlist[i*prime[j]]=true;
if(i%prime[j]==0) break;
}
}
}
//高精度
void mult(int a){
for(int i=0;i<res.size();i++)
res[i]*=a;
for(int i=0;i<res.size()-1;i++){
if(res[i]>=10){
res[i+1]+=res[i]/10;
res[i]%=10;
}
}
while(res[res.size()-1]>=10){
int u=res.size()-1;
res.push_back(res[u]/10);
res[u]%=10;
}
}
int main(){
Eular();
scanf("%d%d",&a,&b);
//处理出所有的公约数
for(int i=1;i<=cnt;i++){
int u=a;
while(u){
num[i]+=u/prime[i];
u/=prime[i];
}
u=b;
while(u){
num[i]-=u/prime[i];
u/=prime[i];
}
u=a-b;
while(u){
num[i]-=u/prime[i];
u/=prime[i];
}
}
res.push_back(1);
//高精度乘法
for(int i=1;i<=cnt;i++){
if(num[i]!=0){
for(int j=1;j<=num[i];j++){
mult(prime[i]);
}
}
}
for(int i=res.size()-1;i>=0;i--)
printf("%d",res[i]);
puts("");
return 0;
}
卡特兰数
对于一个只由01构成的长度为2n的序列,要求其任意前缀都有0的个数大于1的个数,因此可以通过转化为在网格图中的路径表示来证明一共有:
C
2
n
n
−
C
2
n
n
−
1
=
C
2
n
n
⋅
1
n
+
1
C_{2n}^{n}-C_{2n}^{n-1}=C_{2n}^{n}\cdot\ \frac{1}{n+1}
C2nn−C2nn−1=C2nn⋅ n+11
种方案数