xtu 1260 Determinant [2017年“嘉杰信息杯” 中国大学生程序设计竞赛全国邀请赛(湖南) A题]

Determinant

Bobo learned the definition of determinant  det(A)  of matrix  A  in ICPCCamp. He also knew determinant can be computed in  O(n3)  using Gaussian Elimination.

Bobo has an  (n1)×n  matrix  B  he would like to find  det(Bj)  modulo  (109+7)  for all  j{1,2,,n}  where  Bj  is the matrix after removing the  j -th column from  B .

Input

The input contains zero or more test cases and is terminated by end-of-file. For each test case:

The first line contains an integer  n . The  i -th of following  n  lines contains  n  integers  Bi,1,Bi,2,,Bi,n .

  • 2n200
  • 0Bi,j<109+7
  • The sum of  n  does not exceed  2000 .

Output

For each case, output  n  integers which denote the result.

Sample Input

2
2 0
3
1 2 0
6 3 1

Sample Output

0 2
2 1 999999998

题意: 给你一个(n - 1)行n列的行列式, 求去掉第i(1 <= i <= n)行后行列式的值.

思路: 在原有行列式上加一行, 补全成n * n的矩阵, 然后利用高斯消元求得原有矩阵的伴随矩阵. 假设求得伴随矩阵为b, 则b[i][j]就是原有行列式的余子式, b[i][1]对应的就是去掉第i行后行列式的值, 原理参加下面行列式的性质.

行列式的性质: 以三阶矩阵为例, 若 A* 为 A 的伴随矩阵, 则有:

            a11a12 a13

 A =     a21a22 a23

            a31 a32 a33

 

            A11A21 A31

A* =     A12 A22 A32

             A13 A23 A33

其中Aij是aij对应的代数余子式. 在本题中余子式A11对应的就是去掉第一行第一列后行列式的值, 由于第一行是自己增加的, 所以A11就是去掉第一列后行列式的值. 


代码如下:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;

const int maxn = 205;
const ll mod = 1e9 + 7;
ll a[maxn][maxn], b[maxn][maxn];

ll inv_(ll a, ll k) {
    ll res = 1;
    while(k){
        if(k & 1) res = res * a % mod;
        a = a * a % mod;
        k >>= 1;
    }
    return res;
}

void solve(int n) {
    memset(b, 0, sizeof b);
    for(int i = 1; i <= n; i++) b[i][i] = 1;
    ll det = 1;
    for(int i = 1; i <= n; i++) {
        int t;
        for(t = i; t <= n; t++) {
            if(a[t][i]) break;
        }
        if(t != i) det *= -1;
        for(int j = 1; j <= n; j++) {
            swap(a[i][j], a[t][j]);
            swap(b[i][j], b[t][j]);
        }
        det = (det * a[i][i] % mod + mod) % mod;
        ll inv = inv_(a[i][i], mod - 2); //a[i][i]的逆元
        for(int j = 1; j <= n; j++) {
            a[i][j] = inv * a[i][j] % mod;
            b[i][j] = inv * b[i][j] % mod;
        }
        for(int k = 1; k <= n; k++) {
            if(k == i) continue;
            ll tmp = a[k][i];
            for(int j = 1; j <= n; j++) {
                a[k][j] = (a[k][j] - a[i][j] * tmp % mod + mod) % mod;
                b[k][j] = (b[k][j] - b[i][j] * tmp % mod + mod) % mod;
            }
        }
    }
    det = (det + mod) % mod;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j<= n; j++) {
            b[i][j] = det * b[i][j] % mod;  //将b由逆矩阵变成伴随矩阵
        }
    }
}

int main(void){
    int n;
    while(scanf("%d",&n)!=EOF){
        for(int i = 1; i <= n; i++) a[1][i] = 1;
        for(int i = 2; i <= n; i++)
            for(int j = 1; j <= n; j++)
                scanf("%lld", &a[i][j]);
        solve(n);
        for(int i = 1; i <= n; i++)
            printf("%lld%c",(i & 1 ? b[i][1] : (mod - b[i][1]) % mod), i == n ? '\n' : ' ');
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值