高斯消元
求解线性方程组,其实就是线代求解,思想是利用增广矩阵来求
高斯消元的步骤(线代hh):
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 110;
const double eps = 1e-6;
int n;
double a[N][N];
int gauss()
{
int c, r;
for(c=0,r=0;c<n;c++)
{
int t = r;
for(int i=r;i<n;i++)//从第r行开始,前面r行已经确定
{
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]);// 从第c列开始交换,前面c列都已经是0了,从0也可以
for(int j=n;j>=c;j--) a[r][j] /= a[r][c];//要从后开始化1
for(int i=r+1;i<n;i++)
{
if(fabs(a[i][c]) > eps)
{
for(int j=n;j>=c;j--)
{
a[i][j] += ( (-1) * a[i][c] * a[r][j]);//每一个数都要减去当前这行的第c列乘以已经确定的r行的当前列j列
}
}
}
r++;
}
if(r< n)
{
for(int i=r;i<n;i++)
{
if(fabs(a[i][n]) > eps)//0 = !0,所以无解
return 2;
}
return 1;
}
for(int i=n-1;i>=0;i--)
{
for(int j=i+1;j<n;j++)
{
a[i][n] += ((-1) * a[i][j] * a[j][n]);//每一行的b都要减去这一行中非0的值乘以对应列的b
}
}
return 0;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
for(int j=0;j<n+1;j++)
{
cin>>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("Infinite group solutions");
else puts("No solution");
return 0;
}
求组合数
根据问题不同来判定使用哪种方法来解组合数问题
1、给定n 组询问,每组询问给定两个整数 a,b,求出 mod (1e9+7) 的值。
n最大10万,a、b小于2000;
代码思路:递推(复杂度400万左右)
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2010, mod = 1e9 + 7;
int c[N][N];
int 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()
{
int n;
cin>>n;
init();
while(n--)
{
int a, b;
cin>>a>>b;
cout<<c[a][b]<<endl;
}
return 0;
}
2、问题与1相同,但是n最大为1万,a、b小于10万
代码思路:预处理出阶层,逆元的阶层,然后用快速幂求逆元
由费马定理得b的p-1次方与1同余P,所以b的乘法逆元就是b的p-2次方,当p为质数时才成立。
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100010, mod = 1e9 + 7;
typedef long long LL;
int fact[N], 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;
}
int main()
{
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;
}
int n;
cin>>n;
while(n--)
{
int a, b;
cin>>a>>b;
cout<<(LL) fact[a] * infact[b] % mod * infact[a-b] % mod<<endl;
}
return 0;
}
3、20组询问,a,b为10的18次方,p小于10的5次方
思路:卢卡斯定理(画线行)
代码:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int p;
int qmi(int a, int k)
{
int res = 1;
while(k)
{
if(k & 1) res = (LL) res * a % p;
k >>= 1;
a = (LL) a * a % p;
}
return res;
}
int C(int a, int b)
{
int res = 1;
for(int i=1, j=a;i<=b;i++, j--)
{
res = (LL) res * j % p;
res = (LL) res * qmi(i, p-2) % p;
}
return res;
}
LL lucas(LL a, LL b)
{
if(a < p && b < p) return C(a, b);
return (LL) C(a % p, b % p) * lucas(a / p, b / p) % p;
}
int main()
{
int n;
cin>>n;
while(n--)
{
LL a, b;
cin>>a>>b>>p;
cout<<lucas(a, b)<<endl;
}
return 0;
}
4、求组合数4
a,b小于5000,但是求的就是 ,没有模,数可能很大,需要用高精度来求
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 5010;
int primes[N], cnt;
int sum[N];
bool st[N];
int get_primes(int n)
{
for(int i=2;i<=n;i++)
{
if(!st[i]) primes[cnt++] = i;
for(int j=0;primes[j]<=n/i;j++)
{
st[primes[j] * i] = true;
if(i % primes[j] == 0) break;
}
}
}
int get(int n, int p)
{
int res = 0;
while(n)
{
res += n/p;
n /= p;
}
return res;
}
vector<int> mul(vector<int> a, int b)
{
vector<int> c;
int t = 0;
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;
}
int main()
{
int a, b;
cin>>a>>b;
get_primes(a);
for(int i=0;i<cnt;i++)
{
int p = primes[i];
sum[i] = get(a, p) - get(b, p) - get(a - b, p);
}
vector<int> res;
res.push_back(1);
for(int i=0;i<cnt;i++)
{
for(int j=0;j<sum[i];j++)
{
res = mul(res, primes[i]);
}
}
for(int i=res.size()-1;i>=0;i--) cout<<res[i];
cout<<endl;
return 0;
}
5.卡特兰数
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10, mod = 1e9 + 7;
int qmi(int a, int k, int p)
{
int res = 1;
while(k)
{
if(k & 1) res =(LL) res * a % mod;
k >>= 1;
a = (LL) a * a % mod;
}
return res;
}
int main()
{
int n;
cin>>n;
int a = 2 * n, b = n;
int res = 1;
for(int i=a;i>a-b;i--) res = (LL) res * i % mod;
for(int i=1;i<=b;i++) res = (LL) res * qmi(i, mod - 2, mod) % mod;
res = (LL) res * qmi(n + 1, mod - 2, mod) % mod;
cout<<res<<endl;
return 0;
}