数学基础知识
线性筛
略
高斯消元
通过高斯消元,我们可以再
O
(
n
3
)
O(n^3)
O(n3)的时间复杂度内求出线性方程组的解
{
a
11
x
1
+
a
12
x
2
+
⋯
+
a
1
n
x
n
=
b
1
a
21
x
1
+
a
22
x
2
+
⋯
+
a
2
n
x
n
=
b
2
⋮
a
n
1
x
1
+
a
n
2
x
2
+
⋯
+
a
n
n
x
n
=
b
n
\begin{cases} a_{11} x_1+a_{12}x_2+\dots+a_{1n}x_n=b_1\\ a_{21} x_1+a_{22}x_2+\dots+a_{2n}x_n=b_2\\ \vdots\\ a_{n1} x_1+a_{n2}x_2+\dots+a_{nn}x_n=b_n\\ \end{cases}
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧a11x1+a12x2+⋯+a1nxn=b1a21x1+a22x2+⋯+a2nxn=b2⋮an1x1+an2x2+⋯+annxn=bn
解 { 无 解 无 穷 多 组 解 唯 一 解 解\begin{cases} 无解\\ 无穷多组解\\ 唯一解\\ \end{cases} 解⎩⎪⎨⎪⎧无解无穷多组解唯一解
操作:
- 把某一行乘一个非零的数
- 交换某两行
- 把某行的若干倍加到其他行上
初等行列变换
我们通过这些操作,将系数矩阵消乘成上三角矩阵
上三角矩阵:
{
a
11
x
1
+
a
12
x
2
+
⋯
+
a
1
n
x
n
=
b
1
a
22
x
2
+
⋯
+
a
2
n
x
n
=
b
2
⋮
a
n
n
x
n
=
b
n
\begin{cases} a_{11} x_1+a_{12}x_2+\dots+a_{1n}x_n=b_1\\ a_{22}x_2+\dots+a_{2n}x_n=b_2\\ \vdots\\ a_{nn}x_n=b_n\\ \end{cases}
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧a11x1+a12x2+⋯+a1nxn=b1a22x2+⋯+a2nxn=b2⋮annxn=bn
得到这个矩阵后.我们倒着把它消回去
如何判断解的情况呢?
{
完
美
阶
梯
型
:
唯
一
解
0
=
非
0
:
无
解
0
=
0
:
有
无
穷
多
组
解
\begin{cases} 完美阶梯型:唯一解\\ 0=非0:无解\\ 0=0:有无穷多组解\\ \end{cases}
⎩⎪⎨⎪⎧完美阶梯型:唯一解0=非0:无解0=0:有无穷多组解
具体过程:
- 枚举每一列
- 找到当前列绝对值最大的一行
- 将该行换到最上面
- 将该行第一个数的系数变成 1 1 1
- 将下面所有行的当前列消成 0 0 0
- 固定这一行
最后我们得到了一个对角线矩阵
这不就是暴力嘛…
/*************************************************************************
> File Name: p3389[模板]高斯消元法.cpp
> Author: Typedef
> Mail: 1815979752@qq.com
> Created Time: 2021/3/6 21:06:56
> Tags:
************************************************************************/
#include<bits/stdc++.h>
using namespace std;
const int N=110;
const double eps=1e-6;
double a[N][N];
int n;
int gauss(){
int c,r;
for(c=0,r=0;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;i++) swap(a[t][i],a[r][i]);
for(int i=n;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;j>=c;j--)
a[i][j]-=a[r][j]*a[i][c];
r++;
}
if(r<n){
for(int i=r;i<n;i++)
if(fabs(a[i][n])>eps)
return 2;//无解
return 1;//无穷多组解
}
for(int i=n-1;i>=0;i--)
for(int j=i+1;j<n;j++)
a[i][n]-=a[i][j]*a[j][n];
return 0;//有唯一解
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++)
for(int j=0;j<n+1;j++)
scanf("%lf",&a[i][j]);
int t=gauss();
if(t==0){
for(int i=0;i<n;i++) printf("%.2lf\n",a[i][n]);
}
else if(t==1) puts("No Solution");
else puts("No Solution");
system("pause");
return 0;
}
求组合数
lv.1
C a b = a × ( a − 1 ) × ⋯ × ( a − b + 1 ) 1 × 2 × 3 × ⋯ × b = a ! b ! ( a − b ) ! C_a^b=\frac{a\times(a-1)\times\dots\times(a-b+1)}{1\times2\times3\times\dots\times b}=\frac{a!}{b!(a-b)!} Cab=1×2×3×⋯×ba×(a−1)×⋯×(a−b+1)=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(不选+选)
这样可以预处理出所有组合数,询问直接查表即可
/*************************************************************************
> File Name: 885求组合数1.cpp
> Author: Typedef
> Mail: 1815979752@qq.com
> Created Time: 2021/3/6 22:26:40
> Tags:
************************************************************************/
#include<bits/stdc++.h>
using namespace std;
const int N=2010,mod=1e9+7;
int c[N][N];
void init(){
for(int i=0;i<N;i++)
for(int j=0;j<=i;j++)
if(!j) c[i][j]=1;
else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
int main(){
init();
int n;
scanf("%d",&n);
while(n--){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",c[a][b]);
}
system("pause");
return 0;
}