Not Another Linear Algebra Problem 题解
题意:自己看。
首先我们知道我们唯一能找到的题解在 hos_lyric 的代码里。把它放在这里:(由 bikuhiku 提供)
然后对着这个东西一句一句翻译即可得到正解怎么写)
因为没有官方题解,来一发民间题解。当然写的可能不准,因为作者线代水平十分民科。
首先当然是观察这个形式。肯定要在所有 \(\mathbb F_p^n\) 的所有子空间 \(U\) 上讨论 \(B\) 的每个向量在上边的取值。那么设 \(a_i\) 为 \(i\) 维极大子空间 \(U\),计数里边的 \(\mathbb F_p^n\) 的自同构中在 \(U\) 上为平凡同构的同构个数。另设 \(b_i\) 为 \(\ge i\) 维子空间 \(U\) 计数上述同构的个数(也就是上边的 \(a,b\)),即有显然的式子:枚举 \(i\) 的母空间维数 \(j\),那么剩下的子空间个数为 \(\begin{bmatrix}n-i\\ n-j\end{bmatrix}_q\) (必须在剩下 \(n-i\) 维里选正好 \(n-j\) 维,因为 \(\det B\neq 0\)),即有
这个形式好膈应,翻转 \(a,b\):
这个形式看上去好多了。(感觉上是可以 q- 二项式反演的,但是我写了写没写出来)
考虑列出 \(a,b\) 的生成函数:
容易发现上边的式子可以写成卷积形式:
我们需要计算 \(A(x)\),然而卷积是不行的,考虑递推系数。
先看如何算一项 \(b_i\):定了 \(n-i\) 维是恒等置换,那么剩下的随意,即
将这个代入 \(B(x)\),分子分母拆开,一些 dirty work 可以得到
这个递推可以直接找 \(xB(x)\):
那么显然 \(B(qx)=1-q^nxB(x)\)。回代 \(A(x)\) 并提取系数可以直接得到递推式:
这是钦定了 \(i\) 的贡献,对于所有的还要给每个 \(a_i\) 乘上 \(\begin{bmatrix}n\\i\end{bmatrix}_q\)。最后统计答案时,定了 \(i\) 维为恒等置换的 \(B\) 对应的 \(A\) 中这 \(i\) 维可以随意选,即 \(q^{ni}\),而剩下的是定死的,即 \(f(B)=q^{ni}\)。写个光速幂即可。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;
int n,q,mod,ord,jc[10000010],inv[10000010],pw[10000010],cpw[10000010],a[10000010],jcp[10000010],invp[10000010];
int C(int n,int m){
int rn=n%ord,rm=m%ord;
n/=ord;m/=ord;
if(n<m||rn<rm)return 0;
return 1ll*jc[n]*inv[m]%mod*inv[n-m]%mod*jcp[rn]%mod*invp[rm]%mod*invp[rn-rm]%mod;
}
int qpow(int a,int b,int mod){
int ans=1;
while(b){
if(b&1)ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return ans;
}
struct node{
int sq=1<<16,pw[1<<17],gpw[1<<17];
node(){
pw[0]=gpw[0]=1;
for(int i=1;i<sq;i++){
pw[i]=3ll*pw[i-1]%mod;
}
gpw[1]=3ll*pw[sq-1]%mod;
for(int i=2;i<sq;i++)gpw[i]=1ll*gpw[i-1]*gpw[1]%mod;
}
int get(int n){
return 1ll*gpw[n/sq]*pw[n%sq]%mod;
}
};
int main(){
scanf("%d%d%d",&n,&q,&mod);jc[0]=inv[0]=inv[1]=1;
node P;
for(int i=2;i<=n;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=n;i++)jc[i]=1ll*jc[i-1]*i%mod,inv[i]=1ll*inv[i-1]*inv[i]%mod;
pw[0]=cpw[0]=1;pw[1]=q;
for(int i=1;i<=n;i++)pw[i]=1ll*pw[i-1]*pw[1]%mod,cpw[i]=1ll*cpw[i-1]*pw[i-1]%mod;
ord=n+1;
for(int i=1;i<=n;i++)if(pw[i]==1){
ord=i;break;
}
jcp[0]=invp[0]=1;
for(int i=1;i<=n;i++)jcp[i]=1ll*jcp[i-1]*(1-pw[i]+mod)%mod;
invp[n]=qpow(jcp[n],mod-2,mod);
for(int i=n-1;i>=1;i--)invp[i]=1ll*invp[i+1]*(1-pw[i+1]+mod)%mod;
a[0]=1;int invpw=qpow(q,mod-2,mod);
for(int i=1,Inv=1;i<=n;i++){
Inv=1ll*Inv*invpw%mod;
a[i]=1ll*(1ll*((i&1)?(mod-1):1)*cpw[i]+1ll*(pw[i-1]-pw[n]+mod)%mod*(1-pw[i]+mod)%mod*a[i-1])%mod*Inv%mod;
}
for(int i=0;i<=n;i++)a[i]=1ll*a[i]*C(n,i)%mod;
int ans=0,ret=qpow(q,n,mod-1);
if(!ret)ret=mod-1;
for(int i=0,tmp=1;i<=n;i++){
ans=(ans+1ll*P.get(tmp)*a[n-i])%mod;
tmp=1ll*tmp*ret%(mod-1);
}
printf("%d\n",ans);
return 0;
}