传送门
题解:
这道题的原理部分请看这篇题解:https://blog.csdn.net/zxyoi_dreamer/article/details/100160980
上面这篇题解里面的记号全部沿用。
这里主要讲一下这道题怎么用线代黑科技优化常数。
如果一个数列是线性递推数列,设其OGF为 G ( x ) G(x) G(x),则存在两个有限多项式 P ( x ) , Q ( x ) P(x),Q(x) P(x),Q(x),使得 G ( x ) = P ( x ) Q ( x ) G(x)=\frac{P(x)}{Q(x)} G(x)=Q(x)P(x),且 Q ( x ) Q(x) Q(x)常数项为1。
这道题里面我们可以发现对于 G i ( x ) G_i(x) Gi(x),其常数项为 0 0 0,则 F i ( x ) = 1 1 − G i ( x ) F_i(x)=\frac{1}{1-G_i(x)} Fi(x)=1−Gi(x)1,所以 f ( i , k ) f(i,k) f(i,k)也是线性递推数列,并且其线性递推式可以直接从 g ( i , k ) g(i,k) g(i,k)的线性递推式得到。具体的推导过程我就咕咕咕了。
那么现在问题就是怎么求 g ( i , k ) g(i,k) g(i,k)的递推式,也就是转移矩阵 A \mathbf A A的特征多项式。
可以用 O ( n 4 ) O(n^4) O(n4)求出前几项后用BM算法。
但是求一般矩阵特征多项式的算法复杂度就是 O ( n 4 ) O(n^4) O(n4)。。。
下面介绍两种方式求矩阵的特征多项式,记为 c h a r ( A ) = λ n − ∑ i = 0 n − 1 c i λ i \mathrm{char}(\mathbf A)=\lambda^n-\sum_{i=0}^{n-1}c_i\lambda^i char(A)=λn−∑i=0n−1ciλi
1.根据定义
c
h
a
r
(
A
)
=
d
e
t
(
λ
I
−
A
)
\mathrm{char}({\mathbf A})=\mathrm {det}(\lambda \mathbf I-\mathbf A)
char(A)=det(λI−A),代入
λ
=
1
,
2
,
⋯
n
\lambda=1,2,\cdots n
λ=1,2,⋯n,然后高斯消元解行列式和多项式即可,或者代入单位根,之后直接用IDFT可以得到原多项式。
2.考虑利用牛顿恒等式,假设
n
n
n个特征根为
λ
1
,
λ
2
⋯
λ
n
\lambda_1,\lambda_2\cdots\lambda_n
λ1,λ2⋯λn,有
t
r
(
A
k
)
=
∑
i
=
1
n
λ
i
k
\mathrm tr(\mathbf A^k)=\sum_{i=1}^n\lambda_i^k
tr(Ak)=∑i=1nλik,然后利用牛顿恒等式还原回去就行了。
关于牛顿恒等式:
假设 n n n次多项式 A ( x ) = ∑ i = 0 n a i x i A(x)=\sum_{i=0}^na_ix^i A(x)=∑i=0naixi的 n n n个根分别为 x 1 , x 2 ⋯ x n x_1,x_2\cdots x_n x1,x2⋯xn,设 b i = a n − i b_i=a_{n-i} bi=an−i,设 S k = ∑ i = 1 n x i k S_k=\sum_{i=1}^nx_i^k Sk=∑i=1nxik,则有 ∀ k ∈ N ∗ , ∑ i = 1 k S i b k − i + k ⋅ b k = 0 \forall k\in \mathbb N^*,\sum_{i=1}^kS_ib_{k-i}+k\cdot b_k=0 ∀k∈N∗,i=1∑kSibk−i+k⋅bk=0
在知道 S i S_i Si之后可以愉快地反解系数了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;
while(!isdigit(c=gc()));T num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int mod=998244353;
inline int add(int a,int b){a+=b-mod;return a+(a>>31&mod);}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b,int res=1){
for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));
return res;
}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
cs int N=77,M=2e4+7;
int n,m;
int A[N][N];
int way[N][N][N];
int tr[N],coef[N],tp[N];
int ans[N][M];
signed main(){
#ifdef zxyoi
freopen("travel.in","r",stdin);
#endif
n=gi(),m=gi();
for(int re i=0;i<n;++i){
way[0][i][i]=1;
for(int re j=0;j<n;++j)A[i][j]=gi();
}
for(int re t=1;t<=n;++t)
for(int re i=0;i<n;++i)
for(int re j=0;j<n;++j)if(int v=way[t-1][i][j])
for(int re k=0;k<n;++k)Inc(way[t][i][k],mul(v,A[j][k]));
for(int re i=1;i<=n;++i)
for(int re j=0;j<n;++j)Inc(tr[i],way[i][j][j]);
coef[0]=1;
for(int re i=1;i<=n;++i){
for(int re j=0;j<i;++j)
coef[i]=dec(mul(coef[j],tr[i-j]),coef[i]);
Mul(coef[i],power(i,mod-2));
}
for(int re i=1;i<=n;i+=2)coef[i]=dec(0,coef[i]);
for(int re t=1;t<=n;++t){
memset(tp,0,sizeof(int)*n);
for(int re i=0;i<n;++i)
for(int re j=0;j<n;++j)Inc(tp[i&j],way[t][i][j]);
for(int re i=0;i<n;++i)
for(int re j=0;j<n;++j)if((i|j)==j)Inc(ans[i][t],tp[j]);
}
for(int re t=0;t<n;++t){
memcpy(tp,coef,sizeof(int)*(n+1));
for(int re i=0;i<=n;++i)
for(int re j=0;j<=i;++j)Dec(tp[i],mul(coef[j],ans[t][i-j]));
for(int re i=0;i<=m;++i){
ans[t][i]=i<=n?coef[i]:0;
for(int re j=1,lj=std::min(i,n);j<=lj;++j)
Dec(ans[t][i],mul(ans[t][i-j],tp[j]));
}
}
int res=0;
for(int re i=n-1;~i;--i){
for(int re j=n-1;j>i;--j)if((i|j)==j)
for(int re s=1;s<=m;++s)Dec(ans[i][s],ans[j][s]);
for(int re s=1;s<=m;++s)res^=ans[i][s];
}
cout<<res<<"\n";
return 0;
}