转载请注明:http://blog.csdn.net/jiangshibiao/article/details/24960107
【原题】
30%的数据,满足 2 <= N <= 5 ; 1 <= T <= 30 。
100%的数据,满足 2 <= N <= 10 ; 1 <= T <= 1000000000 。
Day2
【分析】首先有一个常识:如果没有路径长度的要求,且给定的邻接矩阵只有0和1表示通与不通的话,从S->E走N次的方案数就是这个矩阵自乘N次后的(S,E)的数值。
我们观察到了一个细节:路径长度范围很小,只有0~9,而且N的范围也很小,只有10。
那么我们可以来拆点。什么意思呢?就是把一个点拆成9个,根据路径的长度来连边。比如路径长度为5,我们就用5条边来连接。构图够好后就是裸的矩阵乘法了。
【代码】
#include<cstdio> #include<cstring> using namespace std; const int mod=2009; struct matrix { int p[105][105],n; }ans,a; matrix operator * (matrix a,matrix b) { matrix c;c.n=a.n; memset(c.p,0,sizeof(c.p)); for (int i=1;i<=a.n;i++) for (int j=1;j<=b.n;j++) for (int k=1;k<=a.n;k++) c.p[i][j]=(c.p[i][j]+a.p[i][k]*b.p[k][j]%mod)%mod; return c; } char s[50]; int i,n,T,j,k,tot; matrix quick(int b) { matrix res;res.n=a.n; for (int i=1;i<=a.n;i++) res.p[i][i]=1; while (b) { if (b&1) res=res*a; b>>=1;a=a*a; } return res; } int main() { scanf("%d%d",&n,&T);a.n=n*9; for (i=1;i<=n;i++) for (j=1;j<=8;j++) a.p[9*(i-1)+j][9*(i-1)+j+1]=1; //点的内部连边 for (i=1;i<=n;i++) { scanf("%s",s); for (j=1;j<=n;j++) if (s[j-1]>'0') a.p[9*(i-1)+s[j-1]-48][9*(j-1)+1]=1; //点的外部连边 } ans=quick(T); printf("%d",ans.p[1][n*9-8]); return 0;