高斯消元、求组合数
- 高斯消元
-
- 组合数
-
- AcWing 885. 求组合数 I
- AcWing 886. 求组合数 II
- AcWing 887. 求组合数 III
- AcWing 888. 求组合数 IV
高斯消元
- 找到当前列绝对值最大的数 所在的行
- 将改行的该列的系数变成1,其他列也要跟着变
- 将这行和最上面未处理的那行交换(不是第一行)
- 最上面那行的以下的所有行的该列消元
- 判断是否存在解 123三种情况
- 若有唯一解,则从最下面开始消元
883. 高斯消元解线性方程组
#include
#include
#include
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[t][c]) < fabs(a[i][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 < c)
{
for (int i = r; i < n; i ++ )
if (fabs(a[i][n]) > eps)
return 2;
return 1;
}
for (int i = r; i >= 0; -- i)
for (int j = i + 1; j < n; ++ j)
a[i][n] -= a[i][j] * a[j][n];
return 0;
}
void solve()
{
cin >> n;
for (int i = 0; i < n; ++ i)
for (int j = 0; j <= n; ++ j)
cin >> a[i][j];
int t = gauss();
if (t == 1) puts("Infinite group solutions");
else if (t == 2) puts("No solution");
else
{
for (int i = 0; i < n; i ++ ) printf("%.2lf\n", a[i][n]);
}
}
int32_t main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int T = 1;
while (T --) solve();
return 0;
}
组合数

- 递推就是Cba = Cba-1 + Cb-1a-1
- 预处理就是qmi (logN复杂度)结合模运算里面的逆元
C^b^~a~ = a! / ((a-b)!*b!)
,提前将所有阶乘的逆元和阶乘的值算出来
- lucas定理证明我看了懵懵懂懂,记住结论就行
AcWing 885. 求组合数 I
#include
#include
#include
using namespace std;
const int N = 2e3 + 10, 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 == 0) c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
void solve()
{
int n;
cin >> n;
init();
while (n -- )
{
int a, b;
cin >> a >> b;
cout << c[a][b] << endl;
}
}
int32_t main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int T = 1;
while (T --) solve();
return 0;
}
AcWing 886. 求组合数 II
- 运用组合数的定义,即最基本的运算公式。
- 基本运算公式中含有除法,我们想把除法变成乘法。
- 前面说了除法变乘法,本题正好有取模预算,取模运算下除法变乘法可以用欧拉函数扩展。
- 模又是质数,可以用费马定理,费马定理可以用快速幂将N优化为logN复杂度
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 1e5 + 10, mod = 1e9 + 7;
int fact[N];
int infact[N];
int qmi(int a, int k, int p)
{
int res = 1;
while (k)
{
if (k & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
void solve()
{
int n;
cin >> n;
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i ++ )
{
fact[i] = (LL)fact[i - 1] * i % mod;
infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
}
while (n -- )
{
int a, b;
cin >> a >> b;
printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
}
}
int32_t main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int T = 1;
while (T --) solve();
return 0;
}
AcWing 887. 求组合数 III

#include
#include
#include
using namespace std;
typedef long long LL;
int qmi(int a, int k, int p)
{
LL res = 1;
while (k)
{
if (k & 1) res = res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
int C(LL a, LL b, int p)
{
if (a < b) return 0;
if (b > a - b) b = a - b;
int x = 1, y = 1;
for (int i = 0; i < b; ++ i)
{
x = (LL)x * (a - i) % p;
y = (LL)y * (i + 1) % p;
}
return (LL)x * qmi(y, p - 2, p) % p;
}
int lucas(LL a, LL b, int p)
{
if (a < p && b < p) return C(a, b, p);
return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}
void solve()
{
int n;
cin >> n;
LL a, b;
int p;
while (n -- )
{
cin >> a >> b >> p;
cout << lucas(a, b, p) << endl;
}
}
int32_t main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int T = 1;
while (T --) solve();
return 0;
}
AcWing 888. 求组合数 IV

#include
#include
#include
using namespace std;
const int N = 5e3;
int primes[N], cnt;
int sum[N];
bool st[N];
void init(int a)
{
for (int i = 2; i <= a; ++ i)
{
if (!st[i]) primes[cnt++] = i;
for (int j = 0; primes[j] <= a / i; ++ j)
{
st[i * primes[j]] = true;
if (i % primes[j] == 0) break;
}
}
}
int get(int x, int p)
{
int res = 0;
while (x)
{
res += x / p;
x /= p;
}
return res;
}
vector<int> mul(vector<int> a, int b)
{
int t = 0;
vector<int> C;
for (int i = 0; i < a.size(); ++ i)
{
t += a[i] * b;
C.push_back(t % 10);
t /= 10;
}
while (t)
{
C.push_back(t % 10);
t /= 10;
}
return C;
}
void solve()
{
int a, b;
cin >> a >> b;
init(a);
for (int i = 0; i < cnt; ++ i)
sum[i] = get(a, primes[i]) - get(a - b, primes[i]) - get(b, primes[i]);
vector<int> res;
res.push_back(1);
for (int i = 0; i < cnt; ++ i)
for (int j = 1; j <= sum[i]; ++ j)
res = mul(res, primes[i]);
for (int i = res.size() - 1; i >= 0; -- i) cout << res[i];
}
int32_t main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int T = 1;
while (T --) solve();
return 0;
}