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
",a[1][p(n,1)]);
    return 0;
} 
原文地址:https://www.cnblogs.com/ctlchild/p/5131445.html