luogu P4159 [SCOI2009]迷路
考虑距离只存在1的情况。
f[ ] [ ] 为最开始的0,1矩阵,则有转移方程f (t) [i][j] = ∑ f (t-1) [i][k] * f (1) [k][j] ,矩阵快速幂即可
由于距离不一定为1,所以要拆点。。
将一个点拆成8个点,由H(i , j) 向 H( i, j-1)连一条长度为1的边( 0<=j<=8 )
然后呢,若一个点 x 到 y 的距离的为 d (d>0) ,那么只需由H(x,0) 向H(y , d-1)连一条长度为1的边 。
(H函数就是一个点的标号,有很多写法,我写的是 return ( i - 1) * 9 + j ; 只要不重复即可)
每转移一次,就相当于走了一秒,走了一个单位距离,H(x , 0) 到 H(y ,0)之间的距离为d,所以在转移 d 次后,就会累加到矩阵中的 ( H ( x, 0) , H (y , 0) )中。。
(不太严谨,依据初始矩阵而定。。)
(假如初始矩阵就是单位矩阵,就是转移d次,假如初始矩阵是你构造的拆点后的矩阵,就是转移d-1次,对应的就是最开始要 t -- )(单位矩阵是对角线上为 1 的矩阵 )
(应该是酱紫。。)
然后就矩阵快速幂。。矩阵快速幂推荐写结构体,可以避免传参啥的。
难在拆点。。(巨佬请无视)
Code
#include<iostream> #include<cstdio> #include<cstring> #define mod 2009 using namespace std; int n,t; char a[20]; inline int read(){ char c=getchar();int x=0,flag=1; while(c<'0' || c>'9'){if(c=='-') flag=-1;c=getchar();} while(c>='0' && c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar(); return x*flag; } int H(int i,int j){return (i-1)*9+j;} struct Node{ int p[210][210]; }ans,f; Node mul(Node a,Node b){ Node c; memset(&c,0,sizeof(c)); for(int i=0;i<=100;i++){ for(int j=0;j<=100;j++){ for(int k=0;k<=100;k++){ c.p[i][j]+=a.p[i][k]*b.p[k][j]%mod;c.p[i][j]%=mod; } } } return c; } int main(){ n=read();t=read(); for(int i=1;i<=n;i++) for(int j=8;j>0;j--) f.p[H(i,j)][H(i,j-1)]=1; for(int i=1;i<=n;i++){ scanf("%s",a+1); for(int j=1;j<=n;j++){ if(a[j]>'0') f.p[H(i,0)][H(j,a[j]-'0'-1)]=1; } } ans=f;t--; for(;t;t>>=1){ if(t&1) ans=mul(ans,f); f=mul(f,f); } printf("%d\n",ans.p[H(1,0)][H(n,0)]);return 0; }