1. 程式人生 > >LUOGU P4159 [SCOI2009]迷路(矩陣乘法)

LUOGU P4159 [SCOI2009]迷路(矩陣乘法)

span clear www. log oid 長度 truct lin scan

傳送門

解題思路

  以前bpw講過的一道題,順便復習一下矩陣乘法。做法就是拆點,把每個點拆成\(9\)個點,然後挨個連邊。之後若\(i\)\(j\)之間的邊長度為\(x\),就讓\(i\)的第\(x\)個點和\(j\)的第\(1\)個點連邊。然後就是一個矩陣快速冪,時間復雜度\(O((n*9)^3log(n*9))\)

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>

using namespace std;
const int MAXN = 15;
const int MOD = 2009;
typedef long long LL;

int n,T,cnt;
LL ans;
char s[MAXN];

struct Matrix{
    int a[105][105];
    void Clear(){
        memset(a,0,sizeof(a));
    }
    friend Matrix operator*(const Matrix A,const Matrix B){
        Matrix C;C.Clear();
        for(register int i=1;i<=90;i++)
            for(register int j=1;j<=90;j++)
                for(register int k=1;k<=90;k++)
                    (C.a[i][j]+=((LL)A.a[i][k]*B.a[k][j]%MOD))%=MOD;
        return C;
    }
}mp,pre;

inline void fast_pow(Matrix x,int y){
    for(;y;y>>=1){
        if(y&1) pre=pre*x;
        x=x*x;
    }
}

int main(){
    int x;
    scanf("%d%d",&n,&T);cnt=n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=8;j++)
            mp.a[(i-1)*9+j][(i-1)*9+j+1]=1;
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        for(int j=1;j<=n;j++){
            x=s[j]-‘0‘;if(x==0) continue;
            mp.a[(i-1)*9+x][(j-1)*9+1]=1;
        }
    }
    pre.Clear();n=n*9;
    for(int i=1;i<=n;i++) pre.a[i][i]=1;
    fast_pow(mp,T);
    cout<<pre.a[1][n-8]<<endl;
    return 0;
}

LUOGU P4159 [SCOI2009]迷路(矩陣乘法)