湘潭CCPC A题

博客讲述了湘潭CCPC竞赛中A题的解决方案,涉及行列式的计算。通过高斯消元法将矩阵转化为阶梯矩阵,然后枚举每一列进行特定操作,以降低复杂度,避免了直接枚举列的O(n³*n)复杂度。在实际操作中需要注意矩阵变换过程中的取模问题,以防结果溢出。
摘要由CSDN通过智能技术生成

Determinant

题意是给有一个n-1行n列的矩阵
让我们求去掉任意一列,得到的行列式的值(模1e9+7),也就是n个答案
最坏的做法枚举每一列然后消元,复杂度O(n³*n),显然不太可行
可以这么做,先做一次高斯消元得到一个阶梯矩阵,然后枚举每一列,枚举到第i列,把i+1到n-1列 往上移动一格,即(做一次消元)
x x x x x x x
0 x x x x x x
0 0 x x x x x
0 0 0 x x x x
0 0 0 0 x x x
0 0 0 0 0 x x
如这样,我们当前枚举到第3列时,
x x x x x x x
0 x x x x x x
0 0 x x x x x
0 0 0 x x x x
0 0 0 0 x x x
0 0 0 0 0 x x
把第4到6列向上做一次消元,然后乘一下,
第一次写矩阵变换,有些地方忘了取模结果爆了long long

  #include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<time.h>
#include<cstdio>
#include<vector>
#include<list>
#include<stack>
#include<queue>
#include<iostream>
#include<stdlib.h>
using namespace std;
#define  LONG long long
const int   INF=0x3f3f3f3f;
const LONG  MOD=1e9+ 7;
const double PI=acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
#define lson  l , mid , rt<< 1
#define rson  mid + 1 ,r , (rt<<1)+1
#define root 1, m , 1
LONG matr[220][229] ;
LONG  ans[220 ] ;
LONG tmp_matr[220][210] ;
LONG Q_pow(LONG a , LONG b)
{
    LONG c =  1;
    while(b)
    {
        if(b&1)
         c = (c * a) % MOD ;
        a = (a * a) % MOD ;
        b /= 2;
    }
    return c ;
}
LONG  Gauss (int n )
{
    LONG sign = 1 ;
    for(int t = 1 ; t <= n ; ++ t)
    {
        if(matr[t][t] == 0 )
        {
            for(int i = t + 1; i <= n ; ++ i)
                if(matr[i][t] != 0 )
                {
                    for(int j = 1 ; j <= n + 1 ; ++j)
                        swap(matr[t][j] , matr[i][j]) ;

                    sign = -sign ;
                    break ;
                }
        }
        for(int i = t +1; i <= n ; ++ i)
        {
            LONG x = matr[i][t] ;
            LONG y = matr[t][t] ;
            if( y == 0) break ;
            if( x == 0) continue ;
            LONG tmp = x * Q_pow(y , MOD - 2 ) % MOD  ;  //这里记得取模 否则下面会爆long long
            for( int j = 1 ; j <= n + 1; ++ j )
                matr[i][j] = ( matr[i][j] - ( matr[t][j] * tmp % MOD ) +MOD )% MOD;
        }
    }
    LONG res = sign ;
    for(int i = 1; i<= n ;++i)
        res = (res * matr[i][i] )% MOD ;
    return (res + MOD )% MOD ;
}
int main()
{
//freopen("/home/weyoung/桌面/in","r",stdin);
//freopen("/home/weyoung/桌面/out2","w",stdout);
    int n ;
    while(cin >> n)
    {
        for(int i = 1 ; i <= n - 1  ; ++i)
            for(int j =1 ; j <= n ;++j)
            cin >> matr[i][j], matr[i][j] = (matr[i][j] + MOD ) % MOD ;
        ans[n] = Gauss(n-1 ) ;
        for(int t = n-1; t >= 1 ; -- t )
        {
            LONG res = 1;
            LONG sign = 1 ;
            for(int i = 1 ;i < n ; ++ i)
                for(int j =1; j<= n ; ++j)
                tmp_matr[i][j] = matr[i][j] ;
                //
            for(int j =1; j <= t-1 ; ++ j )
            res = (res * tmp_matr[j][j]) % MOD ;
            for(int i = t + 1; i < n ; ++ i)
            {
                if(tmp_matr[i-1][i] == 0)
                {
                    sign = - sign ;
                    for(int j = t + 1 ; j<= n ;++j)
                    swap(tmp_matr[i][j] , tmp_matr[i-1][j] ) ;
                }
                else if(tmp_matr[i][i] == 0) continue ;
                else
                {
                    LONG x = tmp_matr[i][i] ;
                    LONG y = tmp_matr[i-1][i] ;
                    LONG temp = x * Q_pow( y , MOD - 2) % MOD ; //这里取模 否则同样会爆long long
                    for(int j = t+ 1 ;j <= n ;++j)
                    tmp_matr[i][j] = ( tmp_matr[i][j] - (tmp_matr[i-1][j] * temp % MOD ) + MOD  ) % MOD ;

                }
                res = (res * tmp_matr[i-1][i]) % MOD ;
            }
            res = ( (res * sign  + MOD ) * tmp_matr[n-1][n] ) % MOD ;;
            ans[t] = (res + MOD) % MOD ;
        }
        for(int i =1; i<= n -1; ++ i)
            cout<<ans[i]<<" " ;
            cout<<ans[n]<<endl;
    }
    return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值