R - Walk
最近 离散小波老师 讲了矩阵快速幂和矩阵乘法
我暂时写不出 美食家 那题
先做了几道相关的题
Atcoder dp contest R - Walk
题目:
求出 满足从 \(i\) 到 \(j\) 经过 \(k\) 条边的路径条数
思路:
单纯的邻接矩阵乘法
\(A_{i,j}^1\):表示\(i → j\),只经过 1 条边的方案数
\(A_{i,j}^2\):表示\(i → j\),只经过 2 条边的方案数
(拆开来看:\(A_{2,3}^1=5,A_{3,6}^1=2 \Rightarrow A_{2,6}^2 +=10\))
... ...
\(A_{i,j}^k\):表示\(i → j\),只经过 k 条边的方案数
其中,
\[A_{i,j}^1=
\begin{cases}
0, e[i][j]=0 \\
1, e[i][j]=1 \\
\end{cases}
\]
代码:
const int MOD=1e9+7;
struct Matrix{
vector<vector<ll>> a;
Matrix(int n){
a.resize(n);
for(int i=0;i<n;++i) a[i].resize(n,0);
}
};
Matrix operator*(const Matrix& A,const Matrix& B)
{
int n=A.a.size();
Matrix C(n);
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
for(int k=0;k<n;++k){
C.a[i][j]=((C.a[i][j]+A.a[i][k]*B.a[k][j])%MOD+MOD)%MOD;
}
}
}
return C;
}
struct Vec{
vector<ll> a;
Vec(int n){
a.resize(n,0);
}
};
Vec operator*(const Matrix& A,const Vec& B){
int n=A.a.size();
Vec C(n);
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
C.a[i]=((C.a[i]+A.a[i][j]*B.a[j])%MOD+MOD)%MOD;
}
}
return C;
}
Matrix qpow(Matrix A,ll k)
{
int n=A.a.size();
Matrix ans(n);
for(int i=0;i<n;++i) ans.a[i][i]=1;//!!!
while(k){
if(k&1) ans=ans*A;
A=A*A;
k>>=1;
}
return ans;
}
int main()
{
int n;ll k;
cin>>n>>k;
Matrix A(n);
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
cin>>A.a[i][j];
}
}
A=qpow(A,k);
ll ans=0;
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
ans=((ans+A.a[i][j])%MOD+MOD)%MOD;
}
}
cout<<ans;
return 0;
}
注意:
这里的\(C\)矩阵,实际上就是\(C=A \times A\)
\(C_{i,j}= \sum_{k=1}^n A_{i,k} \times A_{k,j}\) ,即\(C_{i,j} += A_{i,k} \times A_{k,j}\)
其中每一次计算\(A_{i,k} \times A_{k,j}\),都是相当于是:\(i \rightarrow k \rightarrow j\)是一种方案,统计该方案对\(C_{i,j}\)的贡献
Matrix operator*(const Matrix& A,const Matrix& B)
{
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
for(int k=0;k<n;++k){
C.a[i][j]+=A.a[i][k]*B.a[k][j];
}
}
}
return C;
}

浙公网安备 33010602011771号