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;
}