Determinant 題解

HaHeHyt發表於2024-08-15

link

線性代數還是太線代了,篩法還是太現代了,都好難。。。

下文有許多 attention shock!大家謹慎觀看。

規避分討的,若 \(C=1\),容易打表找規律發現 \(\det(A)=[n\le 2]\)


考慮哈子呢?發現你要麼得幹掉 \(1\) 要麼得幹掉 \(C\)。幹掉 \(C\) 一個未知數太困難了,考慮幹掉 \(1\)

拆!\(1\to C+(1-C)\)。再拆!咋個拆嘞?直接拆出行列式的式子:

\(\det(A)=\sum\limits_{p}(-1)^{\sigma(p)}\prod\limits_{i=1}^n A_{i,p_i}\)

\(A_{i,p_i}\) 中的所有 \(1\)\(C+(1-C)\) 代換,把 \(C,1-C\) 看成兩個元展開。

腦中模擬一下乘法分配律乘出來的樣子,發現一定是若干 \(C^a(1-C)^{n-a}\) 求和。


考慮列舉 \((1-C)^k\) 狀物的貢獻。

為了方便,列舉貢獻的補集 \(S\),此時 \(1-C\) 的貢獻次冪就是 \(n-|S|\) 次,計算 \(C\) 冪次的貢獻:

\(\det(A)=\sum\limits_{S} (1-C)^{n-|S|} {\mathcal{F}} (S)\)


觀察一下,此時包含在 \(S\) 中的 \(p_i=i\) 的貢獻也應該為 \(\times C\),否則貢獻為 \(\times a_{i,p_i}\),構造 \(b_{i,j}=\begin{cases}0\ (j\neq i,j\mid i)\\C\ (\texttt{otherwise})\end{cases}\)

則:\({\mathcal{F}} (S)=\sum\limits_{p} (-1)^{\sigma(p)} \prod\limits_{x\in S} b_{x,p_x}\)

\(p(S)\) 表示排列 \(p\) 保留集合 \(S\) 中的位置構成的新序列

  • 例如 \(p=[2,3,4,7,1,5,6]\)\(p(\{2,3,4,7\})=[3,4,7,6]\)

稍微推過一點線性代數式子的都知道:排列 \(p\) 去掉若干 \(p_i=i\) 的位置逆序對數奇偶性不變!

於是 \({\mathcal{F}}(S)=\sum\limits_{p}(-1)^{\sigma(p(S))} \prod\limits_{x\in S} b_{x,p_x}\),這看著就轉換為了一個新的行列式!

注意到新的行列式中只包含元素 \(\{0,C\}\),於是整體 \(/C\)

此時構造一個邊長為 \(|S|\) 的矩陣 \(\text{Mat}(S):\text{Mat}(S)_{i,j}=C^{-1}\cdot b_{S_i,S_j}=\begin{cases}0\ (S_i\neq S_j,S_i\mid S_j)\\1\ (\texttt{otherwise})\end{cases}\)

此時行列式擴大了 \(C^{|S|}\) 倍,則有:\(\det(A)=\sum\limits_{S} (1-C)^{n-|S|} {\mathcal{F}} (S)=\sum\limits_{S} C^{|S|}(1-C)^{n-|S|} \det(\text{Mat}(S))\)


此時再次套用行列式的定義,\(\det(\text{Mat}(S))\) 顯然轉化為了一個計數問題:

注意到大多數 \(\text{Mat}(S)\) 都存在兩個相同的

即存在 \(x,y\in S,x\neq y\),滿足 \(\{z:z\in S,z\neq x,z\mid x\}=\{z:z\in S,z\neq y,z\mid y\}\)

例如:\(S=\{1,3,4,6\}\),矩陣為:

\(\begin{bmatrix} 1&0&0&0\\ 1&1&1&1\\ 1&1&1&0\\ 1&1&1&1\\ \end{bmatrix}\)

此時第二行第四行完全一致!

腦中模擬從小到大插數的歸納過程,容易歸納發現:

\(\forall S_{i}<S_{j},S_{i}\mid S_j\),即 \(S_1\mid S_2\mid \cdots \mid S_n\)

  • 例如:\(S=\{2,4,12,24\}\) 滿足條件,而 \(S=\{1,3,4,6\}\) 不滿足條件。

顯然滿足條件的 \(S\)\(\text{Mat}(S)\) 為一個左下三角全 \(1\) 的矩陣,此時 \(\det(\text{Mat}(S))=1\)

此時要計數的東西也和 \(|S|\) 相關,列舉之:


\(\det(A)=\sum\limits_{k=0}^n C^k (1-C)^{n-k}f(k)=(1-C)^n\sum\limits_{k=0}^n t^kf(k),t=\dfrac{C}{1-C}\)

其中 \(f(k)\)\(1\le x_1\mid x_2\mid \cdots \mid x_k\le n,x_i\ne x_j\) 的序列 \(x\) 的個數。

這裡 \(x_1\) 可能 $=1 $ 對後續計數有影響,強制欽定 \(x_1\neq 1\)

\(g(k)\)\(1< x_1\mid x_2\mid \cdots \mid x_k\le n,x_i\ne x_j\) 的序列 \(x\) 的個數。

則每個滿足此條件的 \(x\) 都可以選擇:往前插一個 \(1\) 或不幹。於是貢獻要 \(\times (t+1)\)

\(\det(A)=(t+1)(1-C)^n\sum\limits_{k=0}^n t^kg(k)=(t+1)(1-C)^nF(n)\)


考慮遞推 \(F(n)\)

首先有 \(F(1)=1\),其次 \(F(n)=\sum\limits_{k=0}^n t^kg(k)=1+t\sum\limits_{k=0}^{n-1} t^{k}g(k+1)\)

顯然考慮把 \(1< x_1\mid x_2\mid \cdots \mid x_{k+1}\le n,x_i\ne x_j\) 消首項:

\(1< x_2/x_1\mid x_3/x_1\mid \cdots \mid x_{k+1}/x_1\le \lfloor n/x_1\rfloor,x_i\ne x_j\),此時貢獻應該為 \(F(\lfloor n/x_1\rfloor)\)

列舉 \(x_1>1:F(n) =1+t\sum\limits_{x_1=2}^{n} F(\lfloor n/x_1\rfloor)\)啊啦!遞推式終於出來了!


直接樸素記憶化搜尋,複雜度同不預處理的杜教篩為 \(O(n^{0.75})\)。能透過本題。

考慮預處理 \(F(1,2,\cdots ,B)\),其中 \(B=n^{2/3}\),來達到正常杜教篩的 \(O(n^{2/3})\)

直接這樣算顯然複雜度是 \(O(B^{1.5})\) 的,寄啦!

差分下:令 \(G(n)=F(n)-F(n-1)\)\(G\) 的組合意義也是顯然的:

\(h(k)\)\(1< x_1\mid x_2\mid \cdots \mid x_k\ {\color{red}{=}}\ n,x_i\neq x_j\) 的序列 \(x\) 的個數,\(G(n)=\sum\limits_{k=0}^n t^kh(k)\)

此時列舉 \(x_{k-1}\)\(x_k\) 的因子,同上推推,有:\(G(n)=1+t\sum\limits_{d>1,d\mid n} G(d)\)

於是可以調和級數 \(O(B\ln B)\) 預處理 \(G(1,2,\cdots ,n)\),字首和一下得到 \(F\)

  • 啟示:整除分塊差分一下,貢獻可以變成列舉因子!

總複雜度 \(O(B\ln B)\),其中 \(B=n^{2/3}\),足以在 10s 透過 \(n=10^{11}\) 的加強版。

code:

#include<bits/stdc++.h>
#define LL long long
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
using namespace std;
const int N=2e6+5,B=1e7,mod=998244353;
LL n;int sq,c,t,ans,f[N],F[B+5],tot;bool v[N];
inline int to(LL x){return x<=sq?x:tot+1-(n/x);}
inline int md(int x){return x>=mod?x-mod:x;}
inline int ksm(int x,int p){int s=1;for(;p;(p&1)&&(s=1ll*s*x%mod),x=1ll*x*x%mod,p>>=1);return s;}
inline int sol(LL n)
{
	if(n<=B) return F[n];int w=to(n);
	if(v[w]) return f[w];int s=0;
	for(LL i=2,j;i<=n;i=j+1) j=n/(n/i),s=(s+(j-i+1)%mod*sol(n/i))%mod;
	return v[w]=1,f[w]=(1+1ll*t*s)%mod;
}//遞推計算
inline void init(int n)
{
	fill(F+1,F+1+n,1);
	for(int k=2;k<=n;k++)
	{
		F[k]=1ll*F[k]*t%mod;
		for(int j=k+k;j<=n;j+=k) F[j]=md(F[j]+F[k]);
	}
	for(int i=1;i<=n;i++) F[i]=md(F[i]+F[i-1])//字首和一下
}//預處理
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>c;
	if(c==1) return cout<<(n<=2),0;sq=sqrtl(n);
	for(LL i=1,j;i<=n;i=j+1) j=n/(n/i),tot++;
	t=1ll*c*ksm(mod+1-c,mod-2)%mod;init(B);
	ans=1ll*ksm(mod+1-c,n%(mod-1))*(1+t)%mod*sol(n)%mod;//不要忘了前面係數!
	return cout<<ans,0;
}