题解:QOJ#10106. Homeward Glance

题意:给定 \(n\times n\) 的矩阵 \(A\),问有多少 \(n\times n\) 的矩阵 \(B\) 满足 \(AB=BA\)。这里运算都在 \(\bmod p\) 意义下进行,其中 \(p=998244353\)\(1\le n\le 500\)


  • 如果 \(A^n=0\)

\(F=\mathbb F_p\),将 \(A\) 视同 \(V=F^n\) 上的线性映射。\(\ker(T)\) 定义为所有满足 \(Tv=0\) 的向量 \(v\) 的集合。

我们知道有如下的一系列子空间:\(\ker(A)\subseteq \ker(A^2)\subseteq \cdots\subseteq \ker(A^n)=V\)

\(\ker(A)\) 的一组基 \(v_{1,1},\cdots,v_{1,s_1}\),接下来扩充为 \(\ker(A^2)\) 的基 \(v_{1,1},\cdots,v_{1,s_1},v_{2,1},\cdots,v_{2,s_2}\),依次类推,最后得到 \(K\) 的一组基 \(v_{i,j}\),其中 \(1\le i\le n,1\le j\le s_i\)\(s_i=\dim \ker(A^i)-\dim \ker(A^{i-1})\)

事实上,我们可以把基取的「更好看」一点:有 \(v_{i,j}\in \ker(A^i),v_{i,j}\not\in \ker(A^{i-1})\),且有 \(Av_{i,j}\in\ker(A^{i-1})\)。于是可以将 \(A\) 看作 \(\ker(A^i)/\ker(A^{i-1})\to \ker(A^{i-1})/\ker(A^{i-2})\) 的线性映射(其中 \(i\ge 2,A^0=I\)),进一步,这个线性映射还是一个单射。

于是我们得到一些推论:必有 \(s_{i-1}\ge s_{i}\),且我们可以取 \(v_{i,1},\cdots,v_{i,s_i}\) 使得 \(Av_{i,j}=v_{i-1,j}\)\(1\le j\le s_{i}\) 成立。

  • 当然,我们有更简单的方式取这样一组基,也就是先做分解 \(V=F[A]v_1\oplus F[A]v_2\oplus\cdots\oplus F[A]v_k\),然后在每个循环子空间 \(F[A]v\) 内,假设 \(A\) 限制在该子空间内的最小多项式为 \(p^e\),其中 \(\deg p=r\)\(p(x)\) 是一个不可约多项式,且 \(v\) 生成整个子空间。设 \(\deg p=r\),我们取 \(v_{i,j}=p(A)^{i-1}A^{j-1}v\) 即可,其中 \(1\le i\le e,1\le j\le r\)。最后把这些子空间的基合并到一起就好了。

\(B\) 由它在所有 \(v_{i,j}\) 上的作用唯一确定。那么 \(B\) 只需要满足对任意 \(i,j\),有 \(ABv_{i,j}=BAv_{i,j}=Bv_{i-1,j}\)。对于 \(i\ge 2\) 的情况,一旦确定 \(Bv_{i,j}\) 是什么,那么 \(1\le j\le s_i\)\(Bv_{i-1,j}\) 就唯一确定了,而对于 \(s_i< j \le s_{i-1}\)\(Bv_{i-1,j}\) 则可以任意选取;而在 \(i=1\) 的情况,这相当于 \(ABv_{1,j}=BAv_{1,j}=0\),即 \(Bv_{1,j}\in\ker(A)\)

进而有 \(Bv_{1,j}=ABv_{2,j}\in \ker(A)\),那么必须要有 \(Bv_{2,j}\in\ker(A^2)\)。综上我们发现,\(B\) 可以按照如下的步骤确定:对每个 \(1\le i\le n\),以及 \(s_{i+1}< j \le s_i\),我们确定一个 \(Bv_{i,j}\in\ker(A^i)\)。那么其自由度是多少呢?就是

\[\sum_{i=1}^n(s_i-s_{i+1})\times \sum_{j\le i}s_j=\sum_{i=1}^ns_i^2\\ \]

于是,我们只需要求出 \(s_i=\dim\ker(A^i)-\dim\ker(A^{i-1})\),答案就是 \(\sum_{i=1}^ns_i^2\)

  • 一般情况的解法

如果仅仅追求理论上的解法,我们总可以将 \(\mathbb F_p\) 进行扩域(扩域自然不改变解空间维数),使得最小多项式分裂后做上三角化,然后就做完了。然而扩域的代价实在太大了。

首先我们考虑如何求解 \(A\) 的有理标准型,我们设 \(A\) 的最小多项式是 \(m_A(x)=\prod p_i^{e_i}\),可以发现这样一个事实:随机选取 \(v\in V\),满足 \(v\) 相对与 \(A\) 的最小多项式 \(m_{v}(x)\) 大概率就是 \(m_A(x)\),实际上这个概率至少是 \(1-\frac{n}{p}\)。这是因为首先必有 \(m_v(x)\mid m_A(x)\),如果二者不相等那么必须存在 \(p_i\) 使得 \(m_v(x)\mid m_A(x)/p_i\),也就是说 \(v\in \ker(m_A(x)/p_i)\),那么 \(v\) 的取值至多是 \(n\)\(n-1\) 维子空间的并,于是取到这其中的概率就 \(\le \frac{n}{p}\)

那么我们每次随机选取一个向量 \(v\),注意向量乘矩阵是 \(O(n^2)\) 的,我们不断求 \(v,Av,A^2v,\cdots\),直到有一个 \(A^kv\in \text{span}(v,Av,\cdots,A^{k-1}v)\) 为止;此外到这里我们还可以顺便求出 \(A\) 的最小多项式。

接下来在商空间 \(V/F[A]v\) 中接着随机选取向量做下去即可。我们容易在 \(O(\deg m_v(x)\times n^2)\) 的时间复杂度内完成一次分解,那么总的时间复杂度是不超过 \(O(n^3)\) 的。

这个过程至多进行 \(n\) 次,那么我们就有 \((1-\frac{n}{p})^n\ge 1-\frac{n^2}{p}\) 的概率得到 \(V\) 的一个循环分解:\(V=F[A]v_1\oplus F[A]v_2\oplus\cdots\oplus F[A]v_s\),且我们还顺便求出了所有 \(v_i\) 的最小多项式。

这实际上就给出了 \(A\) 的不变因子组 \(d_k(x)\mid d_{k-1}(x)\mid \cdots\mid d_1(x)\)。考虑如何据此求出 \(s_i\)

先假装扩域,使所有 \(d_i(x)\) 分裂,我们还是只需要对每个特征值 \(\lambda\) 对应的广义特征子空间去考虑。假设 \(d_i(x)\)\((x-\lambda)\) 的系数为 \(c_i\),即 \((x-\lambda)^{c_i}\|d_i(x)\),那么可以发现限制在 \(\ker((A-\lambda I)^n)\) 内时,有

\[s_i=\dim\ker(A^i)-\dim\ker(A^{i-1})=\sum_{j=1}^k[c_j\ge i] \]

那么有(注意必有 \(c_i\ge c_{i+1}\)

\[\sum s_i^2=\sum_i\sum_{x,y}[c_x\ge i][c_y\ge i]=\sum_{x,y}\min(c_x,c_y)=\sum_{j=1}^k(2j-1)c_j \]

这就是 \(\lambda\) 对应的解空间维数。

这时候我们发现,并不需要真的求出分裂后的所有多项式,因为上面这个式子是满足可加性的,所以答案其实就是 \(\sum_{j=1}^k(2j-1)\deg d_j(x)\)。综上我们就解决了本题,时间复杂度为 \(O(n^3)\)

碎碎念:EI 的题解里说要对 \(d_i(x)\) 做无平方因子分解,但是好像不需要做这个?

下面的代码写的时候没想清楚,实际上线性基正常写就好了,不用像我这样写。

#include<bits/stdc++.h>

#define ll long long
#define mk make_pair
#define fi first
#define se second

using namespace std;

#define gc getchar
inline int read(){
	int x=0,f=1;char c=getchar();
	for(;(c<'0'||c>'9');c=getchar()){if(c=='-')f=-1;}
	for(;(c>='0'&&c<='9');c=getchar())x=x*10+(c&15);
	return x*f;
}

const int mod=998244353;
int ksm(int x,ll y,int p=mod){
	int ans=1;y%=(p-1);
	for(int i=y;i;i>>=1,x=1ll*x*x%p)if(i&1)ans=1ll*ans*x%p;
	return ans%p;
}
int inv(int x,int p=mod){return ksm(x,p-2,p)%p;}
mt19937 rnd(20070819);
int randint(int l,int r){
	uniform_int_distribution<>dist(l,r);
	return dist(rnd);
}
void add(int &x,int v){x+=v;if(x>=mod)x-=mod;}
void Mod(int &x){if(x>=mod)x-=mod;}
int cmod(int x){if(x>=mod)x-=mod;return x;}

template<typename T>void cmax(T &x,T v){x=max(x,v);}
template<typename T>void cmin(T &x,T v){x=min(x,v);}

int n;
vector<vector<int> >B;
vector<int>I;
void Ins(vector<int>v){
	for(int i=0;i<n;i++)if(v[i]!=0){B[i]=v,I[i]=inv(v[i]);break;}
}
vector<int>rec(vector<int>v){
	for(int i=0;i<n;i++)if(v[i]!=0){
		if(B[i][i]==0)return v;
		int r=1ll*I[i]*v[i]%mod;
		for(int j=i;j<n;j++)add(v[j],mod-1ll*B[i][j]*r%mod);
	}
	return v;
}

struct basis{
	vector<vector<int> >Vs;
	vector<int>ids,invs,vis;int D;
	bool ins(vector<int>v){
		if(vis.empty())vis.resize(n,0),D=0;
		for(int i=0;i<D;i++){
			int p=ids[i];
			for(int j=0;j<n;j++){
				if(v[j]==0&&Vs[p][j]==0)continue;
				if(v[j]==0&&Vs[p][j]!=0)break;
				if(v[j]!=0&&Vs[p][j]==0){
					Vs.emplace_back(v),vis[j]=1;D++;
					ids.insert(ids.begin()+i,D-1);
					invs.emplace_back(inv(v[j]));
					Ins(v);
					return true;
				}

				int r=1ll*invs[p]*v[j]%mod;
				for(int k=j;k<n;k++)add(v[k],mod-1ll*r*Vs[p][k]%mod);
				assert(v[j]==0);break;
			}
		}
		for(int j=0;j<n;j++)if(v[j]!=0){
			Vs.emplace_back(v),ids.emplace_back(D);
			D++,invs.emplace_back(inv(v[j])),vis[j]=1;
			Ins(v);
			return true;
		}
		return false;
	}
};

vector<vector<int> >A;
vector<int>mul(vector<int>v){
	vector<int>res(n,0);
	for(int i=0;i<n;i++)for(int j=0;j<n;j++)add(res[j],1ll*v[i]*A[i][j]%mod);
	return res;
}
vector<int> work(vector<int>v){
	basis W;int cnt=0;
	while(W.ins(v))v=mul(v),v=rec(v);
	return W.vis;
}

signed main(void){

	n=read();A.resize(n,vector<int>(n)),B.resize(n,vector<int>(n)),I.resize(n);
	for(int i=0;i<n;i++)for(int j=0;j<n;j++)A[i][j]=read();
	
	vector<int>ban(n),degs;int sum=0;
	while(sum<n){
		vector<int>vc(n,0);
		for(int i=0;i<n;i++)if(!ban[i])vc[i]=randint(0,mod-1);
		auto vis=work(vc);int now=0;
		for(int i=0;i<n;i++)if(vis[i])ban[i]=1,now++;
		degs.emplace_back(now),sum+=now;
	}

	int ans=0;
	for(int x:degs)for(int y:degs)ans+=min(x,y);
	cout<<ans<<endl;

	return 0;
}
posted @ 2025-04-25 20:25  云浅知处  阅读(89)  评论(0)    收藏  举报