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;
}

 

posted @ 2019-10-18 18:37  dzzx_Syh  阅读(138)  评论(0编辑  收藏  举报