题解: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)\)。那么其自由度是多少呢?就是
于是,我们只需要求出 \(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)\) 内时,有
那么有(注意必有 \(c_i\ge c_{i+1}\))
这就是 \(\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;
}

浙公网安备 33010602011771号