SCOI2009 迷路

传送门


\(ZHX\; TQL\) Orz


我们先考虑边权都是\(1\)的情况,此时只需要一个很简单的DP就可求出答案。

\(dp[i][j]\)表示从i到j的方案总数,则\(dp[i][j]=\sum_{k=1}^n dp[i][k]\cdot dp[k][j]\),虽然我们的方程是正确的,但它会\(\tt{TLE}\)。我们稍加思索,可以发现这个东西和矩阵乘法几乎一模一样,所以我们就可以用矩阵加速\(dp\)

但那是边权都为\(1\)的情况,原问题边权可是\(1\)~\(9\),我们该怎么处理呢?
很简单,暴力拆边就可以了。我们可以把一条边权为\(x\)的边拆成\(x+1\)个点之间连着边权为\(1\)的边。

比如原来的图是这样的:
59vcGd.png

我们可以把它拆成这样:
59vrER.png

然后跑矩阵快速幂就好了。

//底下的注释是我用来调试的,lande
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 2009
using namespace std;
int read(){
    int k=0; char c=getchar();
    for(;c<'0'||c>'9';) c=getchar();
    if(c>='0'&&c<='9')
      k=k*10+c-48;
    return k;
}
struct mat{
    int a[150][150];
}mapp;
int n,t;
mat mul(mat x,mat y){
    mat ans;
    memset(ans.a,0,sizeof(ans.a));
    for(int i=1;i<=9*n;i++)
      for(int j=1;j<=9*n;j++)
        for(int k=1;k<=9*n;k++)
          ans.a[i][k]=(ans.a[i][k]+(x.a[i][j]*y.a[j][k])%mod)%mod;
    return ans;
}
mat poww(mat x,int k){
    mat ans; memset(ans.a,0,sizeof(ans.a));
    for(int i=1;i<=9*n;i++)
      ans.a[i][i]=1;
    for(;k>0;k>>=1){
        if(k&1) ans=mul(ans,x);
        x=mul(x,x);
        /*
        for(int i=1;i<=9*n;i++){
            cout<<endl;
            for(int j=1;j<=9*n;j++)
              cout<<x.a[i][j]<<" ";
        }
        cout<<endl;
        */
    }
    return ans;
}
int main(){
    //freopen("out","w",stdout);
    cin>>n>>t;
    for(int i=0;i<n;i++)
      for(int j=1;j<=8;j++)
        mapp.a[9*i+j][9*i+j+1]=1;
    for(int i=0;i<n;i++)
      for(int j=0;j<n;j++){
        int k=read();
        if(k) mapp.a[9*i+k][9*j+1]=1;
      }
     /* 
    for(int i=1;i<=9*n;i++){
        cout<<endl;
        for(int j=1;j<=9*n;j++)
          cout<<mapp.a[i][j];
    }
    cout<<endl;
    */
    mapp=poww(mapp,t);
    cout<<mapp.a[1][n*9-8];
    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wxl-Ezio/p/9507906.html