题目描述:求行列式的值(模一正数)
分析:
我们要用gauss消元将行列式消成上三角,计算对角线乘积
因为模数不一定是质数,所以gauss消元时不能用费马小定理求逆元了
我们就要用辗转相除法的gauss
每次消元(第jj行)时,默认a[j][i]>a[now][i]a[j][i]>a[now][i](被消元的主元小)
记x=a[j][i]/a[now][i]x=a[j][i]/a[now][i],a[j][k]−=x∗a[now][k]a[j][k]−=x∗a[now][k]
直到a[j][i]=0a[j][i]=0即可
tip
不要忘了计算交换次数取负号
试验了一下,矩阵消成对角线或者上三角都是可以的
当然上三角的复杂度xue微低一点
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
const int N=205;
ll a[N][N],p;
int n;
ll gauss(int n) {
int now=1,to,opt=0;
for (int i=1;i<=n;i++) {
for (to=now;to<=n;to++)
if (a[to][i]) break;
if (to>n) return 0;
if (to!=now) {
for (int j=1;j<=n;j++)
swap(a[to][j],a[now][j]);
opt^=1;
}
for (int j=1;j<=n;j++) if (j!=now) //对角线式
while (a[j][i]) {
int x=a[j][i]/a[now][i];
if (x) {
for (int k=1;k<=n;k++) {
a[j][k]-=x*a[now][k];
a[j][k]=(a[j][k]%p+p)%p;
}
}
else {
for (int k=1;k<=n;k++)
swap(a[j][k],a[now][k]);
opt^=1;
}
}
now++;
}
ll ans=1;
for (int i=1;i<=n;i++) ans=(ans*a[i][i])%p;
if (opt) ans=p-ans;
return ans;
}
int main()
{
while (scanf("%d%lld",&n,&p)!=EOF) {
memset(a,0,sizeof(a));
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) {
scanf("%lld",&a[i][j]);
a[i][j]=(a[i][j]%p+p)%p;
}
printf("%lld\n",gauss(n));
}
return 0;
}