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\)的边。
比如原来的图是这样的:
我们可以把它拆成这样:
然后跑矩阵快速幂就好了。
//底下的注释是我用来调试的,懒得删了
#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;
}