【AT_dp_r】Walk

又是简单题。

我们知道弗洛伊德可以求解传递闭包

我们有矩阵 \(M\),我们给 \(M_{k,i,j}\) 定义为 \(i\to j\) 长度为 \(k\) 的路径数,细想不难发现有转移:

  • \(M_{k,i,j}=\sum\limits_{p=1}^{n} (M_{k-1,i,p}\times M_{1,p,j})\)

直接暴力弗洛伊德得到了 \(kn^3\) 的上天复杂度。

我们发现这实际就是矩阵乘法,\(M_{k}=M_{k-1}\times M_1\)

直接矩阵乘法即可——\(M_k=M_1^k\),结果为 \(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n} M_{k,i,j}\)

得到了 \(O(n^3\log k)\) 的做法。

通过记录

#include <stdio.h>
#include <string.h>
using namespace std;
int n;
long long k;
const int mod=1e9+7;
class Matrix{
	public:
		long long s[105][105];
		void input(){
			for(int i=1;i<=n;i++)
				for(int j=1;j<=n;j++)
					scanf("%lld",&s[i][j]);
		}
		void output(){
			int ret=0;
			for(int i=1;i<=n;i++){
				for(int j=1;j<=n;j++)
					(ret+=s[i][j])%=mod;
			}
			printf("%d",ret);
		}
}ans,mid,a;
Matrix operator *(const Matrix& a,const Matrix& b){
	memset(mid.s,0,sizeof mid.s);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			for(int k=1;k<=n;k++){
				mid.s[i][j]+=a.s[i][k]*b.s[k][j];
				mid.s[i][j]%=mod;
			}
	return(mid);
}
int main(){
	scanf("%d %lld",&n,&k);
	a.input();
	for(int i=1;i<=n;i++)ans.s[i][i]=1;
	while(k>0){
		if(k&1)ans=ans*a;
		a=a*a;
		k>>=1;
	}
	ans.output();
	return(0);
}
posted @ 2023-03-05 14:03  Syara  阅读(21)  评论(0编辑  收藏  举报