如果暴力地把邻接矩阵建出来求解是
O(n3logd)
的,显然无法接受。
我们把矩阵的元素写出来,
Mi,j=∑kx=1Oi,x∗Ij,x
也就是
M=O×IT
这样的话,我们要求的
Md
就可以看成
(OIT)d=O(ITO)d−1I
。中间的矩阵是
k×k
的,这样复杂度就成了
O(k3logd+k2n)
。
还有一个问题,直接矩阵乘法求出来的是恰好
d
步走到,我们可以新建一个节点,从终点和他自己向他连边用来累计答案,这样求走
#include<cstdio>
#include<algorithm>
using namespace std;
#define LL unsigned long long
const int maxn=1010,maxk=25,p=1000000007;
int o[maxn][maxk],it[maxk][maxn],o1[maxn][maxk],i1[maxk][maxn],a[maxn][maxn],
t1[maxn][maxn],t2[maxn][maxn];
int n,k;
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int q,u,v,d,ans;
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++)
{
for (int j=1;j<=k;j++)
scanf("%d",&o[i][j]);
for (int j=1;j<=k;j++)
scanf("%d",&it[j][i]);
}
scanf("%d",&q);
while (q--)
{
scanf("%d%d%d",&u,&v,&d);
for (int i=1;i<=n;i++)
for (int j=1;j<=k;j++)
{
o1[i][j]=o[i][j];
i1[j][i]=it[j][i];
}
for (int i=1;i<=n;i++)
{
o1[i][k+1]=(i==v);
i1[k+1][i]=0;
}
o1[n+1][k+1]=i1[k+1][n+1]=1;
for (int i=1;i<=k+1;i++)
for (int j=1;j<=k+1;j++)
{
a[i][j]=0;
for (int x=1;x<=n+1;x++)
a[i][j]=(a[i][j]+(LL)i1[i][x]*o1[x][j])%p;
}
//mul(i1,o1,k+1,n+1,k+1);
for (int i=1;i<=k+1;i++)
for (int j=1;j<=k+1;j++)
{
t1[i][j]=a[i][j];
a[i][j]=(i==j);
}
while (d)
{
if (d&1)
{
for (int i=1;i<=k+1;i++)
for (int j=1;j<=k+1;j++)
{
t2[i][j]=0;
for (int x=1;x<=k+1;x++)
t2[i][j]=(t2[i][j]+(LL)a[i][x]*t1[x][j])%p;
}
for (int i=1;i<=k+1;i++)
for (int j=1;j<=k+1;j++)
a[i][j]=t2[i][j];
}
d>>=1;
for (int i=1;i<=k+1;i++)
for (int j=1;j<=k+1;j++)
{
t2[i][j]=0;
for (int x=1;x<=k+1;x++)
t2[i][j]=(t2[i][j]+(LL)t1[i][x]*t1[x][j])%p;
}
for (int i=1;i<=k+1;i++)
for (int j=1;j<=k+1;j++)
t1[i][j]=t2[i][j];
}
//pow(d,k+1);
for (int i=1;i<=k+1;i++)
for (int j=1;j<=k+1;j++)
t1[i][j]=a[i][j];
for (int i=1;i<=n+1;i++)
for (int j=1;j<=k+1;j++)
{
a[i][j]=0;
for (int x=1;x<=k+1;x++)
a[i][j]=(a[i][j]+(LL)o1[i][x]*t1[x][j])%p;
}
//mul(o1,a,n+1,k+1,k+1);
ans=0;
for (int i=1;i<=k+1;i++)
ans=(ans+(LL)a[u][i]*i1[i][n+1])%p;
printf("%d\n",ans);
//mul(a,i1,n+1,k+1,n+1);
//printf("%d\n",a[u][n+1]);
}
}