2020 CCPC Wannafly Winter Camp Day7 Div.1&2(重现赛)D 题题解

比赛链接

D. 方阵的行列式

题意

给定一个模 998244353 (质数)意义下的 n × n n\times n n×n 的方阵和 Q Q Q 个修改操作。每个修改操作都修改方阵中某个元素为一个新的值。在每个修改操作后,输出方阵的行列式。

数据范围:

1 ≤ n , Q ≤ 500 1\le n,Q\le 500 1n,Q500

(修改第 x x x 行第 y y y 列的元素为 z z z 1 ≤ x , y ≤ n , 0 ≤ z < 998244353 1\le x,y\le n,0\le z<998244353 1x,yn,0z<998244353

题解

前置知识
  1. Sherman-Morrison formula: 假设 A ∈ R n × n A\in\R^{n\times n} ARn×n 是可逆方阵, u , v ∈ R n u,v\in\R^n u,vRn 是列向量,则 A + u v T A+uv^T A+uvT 可逆当且仅当 1 + v T A − 1 u ≠ 0 1+v^TA^{-1}u\ne 0 1+vTA1u=0,此时有
    ( A + u v T ) − 1 = A − 1 − A − 1 u v T A − 1 1 + v T A − 1 u (A+uv^T)^{-1}=A^{-1}-\frac{A^{-1}uv^TA^{-1}}{1+v^TA^{-1}u} (A+uvT)1=A11+vTA1uA1uvTA1
    成立

  2. 定义:在 n n n 阶行列式中,划去元 a i j a_{ij} aij 所在的第 i i i 行与第 j j j 列的元,剩下的元不改变原来的顺序所构成的 n − 1 n-1 n1 阶行列式称为元 a i j a_{ij} aij余子式,记作 M i j M_{ij} Mij

  3. 定义 a i j a_{ij} aij代数余子式 A i j = ( − 1 ) i + j M i j A_{ij}=(-1)^{i+j}M_{ij} Aij=(1)i+jMij

  4. 定理:当 ∣ A ∣ ≠ 0 |A|\ne 0 A=0 时, A − 1 = 1 ∣ A ∣ A ∗ A^{-1}=\dfrac{1}{|A|}A^* A1=A1A,其中 A ∗ A^* A 的第 ( i , j ) (i,j) (i,j) 元为 A A A 的第 ( j , i ) (j,i) (j,i) 元的代数余子式 A j i A_{ji} Aji A ∗ A^* A 称为 A A A 的伴随方阵。

  5. 展开定理:行列式 Δ \Delta Δ 的值,等于它的任意一行各元分别乘以各自的代数余子式的乘积之和:
    Δ = ∑ j = 1 n a i j A i j . \Delta=\sum_{j=1}^na_{ij}A_{ij}. Δ=j=1naijAij.
    注意:在按行展开的公式
    Δ = a i 1 A i 1 + ⋯ + a i j A i j + ⋯ + a i n A i n \Delta=a_{i1}A_{i1}+\cdots+a_{ij}A_{ij}+\cdots+a_{in}A_{in} Δ=ai1Ai1++aijAij++ainAin
    中,第 i i i 行的各元的代数余子式 A i 1 , ⋯   , A i n A_{i1},\cdots,A_{in} Ai1,,Ain 的值都由 Δ \Delta Δ 中第 i i i 行以外的元决定,与第 i i i 行各元 a i 1 , ⋯   , a i n a_{i1},\cdots,a_{in} ai1,,ain 无关。因此,在行列式 Δ \Delta Δ 中将第 i i i 行各元分别换成任意值 x 1 , ⋯   , x n x_1,\cdots,x_n x1,,xn,得到的行列式 Δ ( x 1 , ⋯   , x n ) \Delta(x_1,\cdots,x_n) Δ(x1,,xn) 按第 i i i 行展开式中的各代数余子式 A i 1 , ⋯   , A i n A_{i1},\cdots,A_{in} Ai1,,Ain 仍与在 Δ \Delta Δ 中相同。

算法步骤
  1. 高斯消元法求 A − 1 A^{-1} A1 ∣ A ∣ |A| A,记 A − 1 = C = ( c i j ) A^{-1}=C=(c_{ij}) A1=C=(cij),复杂度 O ( n 3 ) O(n^3) O(n3)
  2. 执行修改操作,将 ( x , y ) (x,y) (x,y) 元修改为 z z z,改变量记为 d e l t a = z − a x y delta=z-a_{xy} delta=zaxy,改变后的矩阵记为 A ′ = ( a i j ′ ) A'=(a'_{ij}) A=(aij)
  3. 计算修改后的行列式的值 ∣ A ′ ∣ |A'| A,用定理 5 对第 x x x 行按行展开来求,而由定理 4, A i j ′ = A i j = ∣ A ∣ c j i A'_{ij}=A_{ij}=|A|c_{ji} Aij=Aij=Acji,故 ∣ A ′ ∣ = ∑ j = 1 n a x j ′ ∣ A ∣ c j i \displaystyle |A'|=\sum_{j=1}^na'_{xj}|A|c_{ji} A=j=1naxjAcji
  4. ∣ A ∣ = ∣ A ′ ∣ |A|=|A'| A=A,并用定理 1 计算 ( A ′ ) − 1 (A')^{-1} (A)1:令 u = ( 0 , ⋯   , 0 , 1 , 0 , ⋯   , 0 ) T u=(0,\cdots,0,1,0,\cdots,0)^T u=(0,,0,1,0,,0)T(第 x x x 个分量为 1,其它分量为 0 的列向量), v = ( 0 , ⋯   , 0 , d e l t a , 0 , ⋯   , 0 ) T v=(0,\cdots,0,delta,0,\cdots,0)^T v=(0,,0,delta,0,,0)T (第 y y y 个分量为 d e l t a delta delta,其它分量为 0 的列向量),即可在 O ( n 2 ) O(n^2) O(n2) 内算出 ( A ′ ) − 1 = ( A + u v T ) = A − 1 − A − 1 u v T A − 1 1 + v T A − 1 u (A')^{-1}=(A+uv^T)=A^{-1}-\dfrac{A^{-1}uv^TA^{-1}}{1+v^TA^{-1}u} (A)1=(A+uvT)=A11+vTA1uA1uvTA1。然后令 C = A − 1 = ( A ′ ) − 1 , A = A ′ C=A^{-1}=(A')^{-1},A=A' C=A1=(A)1,A=A。回到步骤 2,进行下一步修改操作,直至修改操作结束。

故总时间复杂度 O ( n 3 + Q n 2 ) O(n^3+Qn^2) O(n3+Qn2)

#include<bits/stdc++.h>
using namespace std;
const int N=505,mod=998244353;
int A[N][N],B[N][2*N],C[N][N],D[N][N],E[N][N],F[N][N];
int qpow(int x,int y){
	int ret=1;
	for(;y;x=1ll*x*x%mod,y>>=1)
		if(y&1) ret=1ll*ret*x%mod;
	return ret;
}
void Get_Inverse_1(int n,int& det){
	det=1;
	memset(B,0,sizeof(B));
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) B[i][j]=A[i][j];
	for(int i=1;i<=n;i++) B[i][i+n]=1;
	
	int times=0;
	for(int i=1;i<n;i++){
		if(B[i][i]==0){
			times++;
			int row=-1;
			for(int j=i+1;j<=n;j++)
				if(B[j][i]!=0){
					row=j;
					break;
				}
			if(row==-1) continue;
			for(int k=i;k<=2*n;k++) swap(B[i][k],B[row][k]);
		}
		for(int j=i+1;j<=n;j++){
			int m=1ll*B[j][i]*qpow(B[i][i],mod-2)%mod;
			for(int k=i;k<=2*n;k++){
				B[j][k]=(1ll*B[j][k]-1ll*m*B[i][k]%mod+mod)%mod;
			}
		}
		det=1ll*det*B[i][i]%mod;
	}
	det=1ll*det*B[n][n]%mod;
	if(times&1) det=(mod-det)%mod;
	for(int i=n;i>=1;i--){
		int temp=B[i][i];
		temp=qpow(temp,mod-2);
		B[i][i]=1;
		for(int k=n+1;k<=2*n;k++) B[i][k]=1ll*B[i][k]*temp%mod;
		int temp2=qpow(B[i][i],mod-2);
		for(int j=i-1;j>=1;j--){
			int m=1ll*B[j][i]*temp2;
			for(int k=n+1;k<=2*n;k++){
				B[j][k]=(1ll*B[j][k]-1ll*m*B[i][k]%mod+mod)%mod;
			}
		}
	}
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) C[i][j]=B[i][j+n];
}
int C2[N],C3[N];
void Get_Inverse_2(int n,int x,int y,int delta){
	int deno=(1+1ll*C[y][x]*delta%mod)%mod;
	deno=qpow(deno,mod-2);
	for(int i=1;i<=n;i++) C2[i]=C[i][x],C3[i]=C[y][i];
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++)
			C[i][j]=(1ll*C[i][j]-1ll*C2[i]*delta%mod*C3[j]%mod*deno%mod+mod)%mod;
	}
}
int main(){
	
	int n,q;
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&A[i][j]);
	int det;
	Get_Inverse_1(n,det);
	while(q--){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		int before=A[x][y];
		A[x][y]=z;
		int ans=0;
		for(int j=1;j<=n;j++){
			ans=(1ll*ans+1ll*A[x][j]*C[j][x]%mod*det%mod)%mod;
		}
		printf("%d\n",ans);
		det=ans;
		int delta=(z-before+mod)%mod;
		Get_Inverse_2(n,x,y,delta);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lgwza

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值