[ACNOI2022]线性代数の痛

280 篇文章 1 订阅
本文探讨了在有限域GF(p)上,如何寻找满足特定条件的矩阵A和B,其中B是满秩且A=B×A。通过分析矩阵变换的性质,引入群论中的Burnside引理,计算了等价类数量,从而解决了这类矩阵问题。文章详细解释了矩阵秩、内核与像的关系,并给出了高效的算法实现。
摘要由CSDN通过智能技术生成

题目

题目背景
唉!无力挽留春归去,春去难再聚。回首梧桐风无痕,只有叶犹存。

题目概要
G F ( p ) \mathbb{GF}(p) GF(p) 上找出两个 n × n n{\times} n n×n 矩阵 A , B A,B A,B 使得 det ( B ) ≠ 0 \text{det}(B)\ne 0 det(B)=0 B B B 满秩,且 A = B × A A=B\times A A=B×A 。所有运算在 G F ( p ) \mathbb{GF}(p) GF(p) 上进行。

请求出 ⟨ A , B ⟩ \langle A,B\rangle A,B 的数量,对 998244353 998244353 998244353 取模。

数据范围与提示
n ⩽ 3 × 1 0 7 n\leqslant 3\times 10^7 n3×107 p ⩽ 1 0 9 p\leqslant 10^9 p109 。保证 p p p 为质数。

思路

我的想法是,矩阵相同等价于 ∀ v \forall v v 都有 A × v = ( B × A ) × v A\times v=(B\times A)\times v A×v=(B×A)×v,然后结合律一下得到
∀ v ∈ Im ( A ) ,    v = B × v \forall v\in\text{Im}(A),\;v=B\times v vIm(A),v=B×v

再移项就是
Im ( A ) ⫅ ker ⁡ ( B − I ) \text{Im}(A)\subseteqq\ker(B-I) Im(A)ker(BI)

上面的 I I I 是单位矩阵。容易发现,只需要知道 dim ⁡ ker ⁡ ( B − I ) \dim\ker(B-I) dimker(BI) 即可求出 A A A 的数量。那么问题来了:在条件 dim ⁡ ker ⁡ ( B ) = 0 \dim\ker(B)=0 dimker(B)=0 下,怎么求 dim ⁡ ker ⁡ ( B − I ) \dim\ker(B-I) dimker(BI) 的分布?😵


问题还是出在 det ( B ) ≠ 0 \text{det}(B)\ne 0 det(B)=0 上。出题人其实希望它构成 。又因为 A A A B B B 变化下是封闭的,所以 B B B 就是一种 置换群,我们其实要算 不动点 数量之和。利用 burnside \text{burnside} burnside 定理
∑ g ∈ G ∣ X g ∣ = ∣ G ∣ ⋅ ∣ X / G ∣ \sum_{g\in G}|X^g|=|G|\cdot|X/G| gGXg=GX/G

即不动点的数量之和 = = = 置换数 × \times × 等价类数。看上去很神奇;虽说不用 burnside \text{burnside} burnside 也完全可以推出下面的式子。本题的关键在于——下面我们会说到——等价类大小相同。我觉得它不那么容易发现,却应该可以理解:因为 张成空间相同的矩阵都是相似的

置换数,就是合法的 B B B 的数量。考虑每个行向量,那么第 i i i 个行向量就不能与前 ( i − 1 ) (i{\rm-}1) (i1) 个行向量线性相关;而前 ( i − 1 ) (i{\rm-}1) (i1) 个行向量张成了 ( i − 1 ) (i{\rm-}1) (i1) 维子空间,故该行向量的可选数量是 ( p n − p i − 1 ) (p^n{-}p^{i-1}) (pnpi1),所以
∣ G ∣ = ∏ i = 1 n ( p n − p i − 1 ) |G|=\prod_{i=1}^{n}(p^n-p^{i-1}) G=i=1n(pnpi1)

等价类数,则稍微复杂些。但是我们会震惊地发现,对于秩相同的 A A A等价类大小相同。这个结论可以在下面的推导中发现。

rank ( A ) = k \text{rank}(A)=k rank(A)=k 。首先需要发现的是 rank ( B A ) = k \text{rank}(BA)=k rank(BA)=k,即这种 A A A 对于 B B B 变换是封闭的。只需考察方程 B A v = 0 BAv=0 BAv=0,因 ker ⁡ ( B ) = { 0 } \ker(B)=\{0\} ker(B)={0},其唯一解是 A v = 0 Av=0 Av=0,故 ker ⁡ ( B A ) = ker ⁡ ( A ) \ker(BA)=\ker(A) ker(BA)=ker(A),证毕。

另一方面,我们可以摆脱 det ( B ) ≠ 0 \text{det}(B)\ne 0 det(B)=0 这个约束。即,对于 rank ( A ) = rank ( A ′ ) = k \text{rank}(A)=\text{rank}(A')=k rank(A)=rank(A)=k,若存在任意矩阵 B 0 B_0 B0 使得 A ′ = B 0 A A'=B_0A A=B0A,则存在满秩矩阵 B B B 使得 A ′ = B A A'=BA A=BA 。毕竟 Im ( A ) \text{Im}(A) Im(A) ker ⁡ ( B 0 ) \ker(B_0) ker(B0) 必无交,将 ker ⁡ ( B 0 ) \ker(B_0) ker(B0) 映射到 Im ( B 0 ) \text{Im}(B_0) Im(B0) 以外,就可以让秩扩充到满。

由于 B B B 可以交换 A A A 的两行,不妨规定 A A A 的前 k k k 行是线性无关的——其余情况都假定为 “非法”,不影响等价类数量。那么计算一下 A A A 的数量:与求 ∣ G ∣ |G| G 方法相同,应该是 ∏ i = 0 k − 1 ( p n − p i ) \prod_{i=0}^{k-1}(p^n-p^i) i=0k1(pnpi),然后乘 σ = ( p k ) n − k \sigma=(p^k)^{n-k} σ=(pk)nk 。这个 σ \sigma σ 不重要,等会儿我们会看到。

现在试着计算 A ′ = B A A'=BA A=BA 的不同数量,即等价类的大小。 A ′ A' A 的每个行向量,都是 A A A 的行向量的线性和。以 A A A 的前 k k k 个行向量为基底,则 A ′ A' A 的每个行向量等价于一个 k k k 维向量。而 A ′ A' A 的前 k k k 个行向量就是 k k k 个线性无关 k k k 维向量。用求 ∣ G ∣ |G| G 的方法就能计算。其余行向量任选——注意,不是选线性变换 B B B 的系数,而是选 A ′ A' A 的行向量——方案数也是 σ \sigma σ,也就消掉了。你看,我们算出来,和 A A A 在同一个等价类内的元素数量是常数(与 A A A 无关)!

所以每个等价类大小都是 σ ∏ i = 0 k − 1 ( p k − p i ) \sigma\prod_{i=0}^{k-1}(p^k-p^i) σi=0k1(pkpi),用总数除以它,就得到等价类数量。消掉 σ \sigma σ
∣ X k / G ∣ = ∏ i = 0 k − 1 p n − p i p k − p i |X_k/G|=\prod_{i=0}^{k-1}\frac{p^n-p^i}{p^k-p^i} Xk/G=i=0k1pkpipnpi

∣ X / G ∣ = ∑ k = 0 n ∣ X k / G ∣ |X/G|=\sum_{k=0}^{n}|X_k/G| X/G=k=0nXk/G 也蛮简单。算 ∣ X k / G ∣ |X_k/G| Xk/G 时,分子分母分别算,都可以递推。最后离线求逆元,时间复杂度 O ( k + log ⁡ p ) \mathcal O(k+\log p) O(k+logp)

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
typedef long long llong;
inline int readint(){
	int a = 0, c = getchar(), f = 1;
	for(; !isdigit(c); c=getchar())
		if(c == '-') f = -f;
	for(; isdigit(c); c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}

const int MOD = 998244353;
inline int qkpow(llong b,int q){
	llong a = 1;
	for(; q; q>>=1,b=b*b%MOD)
		if(q&1) a = a*b%MOD;
	return int(a);
}

const int MAXN = 30000005;
int powp[MAXN], mom[MAXN], qzj[MAXN];
int main(){
	int n = readint(), p = readint();
	rep(i,mom[0]=qzj[0]=powp[0]=1,n){
		powp[i] = int(llong(powp[i-1])*p%MOD);
		mom[i] = int(llong(powp[i]-1)
			*powp[i-1]%MOD*mom[i-1]%MOD);
		qzj[i] = int(llong(qzj[i-1])*mom[i]%MOD);
	}
	int inv = qkpow(qzj[n],MOD-2);
	drep(i,n,1){
		const int t = mom[i];
		mom[i] = int(llong(inv)*qzj[i-1]%MOD);
		inv = int(llong(inv)*t%MOD);
	}
	int son = 1, ans = 1; // when i = 0
	rep(i,1,n){
		son = int(llong(powp[n]+MOD-powp[i-1])*son%MOD);
		ans = int((ans+llong(son)*mom[i])%MOD);
	}
	ans = int(llong(ans)*son%MOD);
	printf("%d\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值