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;
}
posted @ 2019-11-14 09:17  MorsLin  阅读(105)  评论(0编辑  收藏  举报