Loading

Determinant 题解

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;
}
posted @ 2024-08-15 22:51  HaHeHyt  阅读(44)  评论(0编辑  收藏  举报