BZOJ1297: [SCOI2009]迷路
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1297
把每个点拆成9个,然后(x,j)→(x,j-1)。
然后如果存在有一条边x→y,权值为w,(x,1)→(y,w),这样的话跑w次矩阵乘法后它的答案才会被累加到((x,1),(y,1))中。
跑T遍矩阵乘法输出((1,1)(n,1))
#include<cstring> #include<iostream> #include<cstdio> #include<queue> #include<cmath> #include<algorithm> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define low(x) (x&(-x)) #define maxn 505 #define inf int(1e9) #define mm 1000000007 #define ll long long using namespace std; int a[105][105],b[105][105],c[105][105]; int n,m,t,x; char s[105]; int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x*f; } int p(int x,int y){ return (x-1)*9+y; } int main(){ n=read(); t=read(); m=n*9; rep(i,1,n) rep(j,2,9) b[p(i,j)][p(i,j-1)]=1; rep(i,1,n) { scanf("%s",s+1); int l=strlen(s+1); rep(j,1,n) { x=s[j]-'0'; if (x!=0) b[p(i,1)][p(j,x)]=1; } } rep(i,1,m) a[i][i]=1; while (t){ if (t&1){ clr(c,0); rep(i,1,m) rep(j,1,m) rep(k,1,m) c[i][j]=(c[i][j]+a[i][k]*b[k][j])%2009; rep(i,1,m) rep(j,1,m) a[i][j]=c[i][j]; } clr(c,0); rep(i,1,m) rep(j,1,m) rep(k,1,m) c[i][j]=(c[i][j]+b[i][k]*b[k][j])%2009; rep(i,1,m) rep(j,1,m) b[i][j]=c[i][j]; t/=2; } printf("%d\n",a[1][p(n,1)]); return 0; }