【Luogu】P4159迷路(矩阵优化)

  题目链接

  将每个点拆成时刻1~9,然后根据题目要求连边,比如i-j有一条权为x的边就从点i-x向点j-1连一条边,表示经过x次之后可以到达。

  然后就矩阵快速幂乱搞就好了。

  

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<cstdlib>
#define maxn 105
#define mod 2009
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int lim;

struct Matrix{
    long long s[maxn][maxn];
    void clear(){memset(s,0,sizeof(s));    }
};

Matrix operator *(Matrix a,Matrix b){
    Matrix ans;    ans.clear();
    for(int i=1;i<=lim;++i)
        for(int j=1;j<=lim;++j)
            for(int k=1;k<=lim;++k)    ans.s[i][j]=(ans.s[i][j]+a.s[i][k]*b.s[k][j]%mod)%mod;
    return ans;
}
    
Matrix Pow(Matrix a,long long b){
    Matrix ret;    ret.clear();
    for(int i=1;i<=maxn;++i)    ret.s[i][i]=1;
    while(b){
        if(b&1)    ret=ret*a;
        a=a*a;
        b>>=1;
    }
    return ret;
}

int n;

int calc(int a,int b){    return a+(b-1)*n;    }

char c[maxn];

int main(){
    Matrix sta;    sta.clear();
    n=read();long long t=read();lim=n*9;
    for(int i=1;i<=n;++i){
        for(int j=1;j<9;++j)    sta.s[calc(i,j)][calc(i,j+1)]++;
        scanf("%s",c+1);
        for(int j=1;j<=n;++j){
            int x=c[j]-'0';
            if(x==0)    continue;
            for(int k=1;k+x-1<=9;++k)    sta.s[calc(i,x+k-1)][calc(j,1+k-1)]++;
        }
    }
    sta=Pow(sta,t);
    //for(int i=1;i<=lim;++i,printf("\n"))
//        for(int j=1;j<=lim;++j)    printf("%lld ",sta.s[i][j]);
    printf("%lld",sta.s[1][n]);
    return 0;
}

 

posted @ 2018-04-14 15:55  Konoset  阅读(185)  评论(0编辑  收藏  举报