SCOI2009 迷路 题解
---恢复内容开始---
题目描述
输入格式
输出格式
样例
数据范围与提示
思路:
这题可以说是一种定理题,在矩阵中,一个存i到j路径数的矩阵自乘k次,a[i][j]表示从i到j走k步的路径数。我们来证明一下,其实仔细理解一下矩阵乘,c[i][j]+=a[i][k]*b[k][j],一写出来就明朗了,枚举一个中间点,用乘法原理,i到j两步的路径数等于i到k一步的路径数乘k到j一步的路径,然后再对于不同的中间点用加法原理,这一定是正确并且全面的,每次都枚举了i能到的所有点,以及能到j的所有点,k步就显然一样。然后会发现这道题并没有被解决,因为他的边权可能为1~9,如果直接存进矩阵的话,存边权显然是不可取的,它表示有边权数条路径,存1好像成了一步就能到。正解是把一个点拆成9个点,可以认为搞一个9进制,然后进行连边,具体实现不好叙述,大概是这样
for(int i=1;i<d;i++) a.a[x*9+i][x*9+i+1]=1; a.a[x*9+d][y*9+1]=1;
然后就可以保证边权是k的时候能够正确处理。
#include<cstdio> #include<iostream> #define ll long long using namespace std; const int mod=2009; struct node{ll a[102][102];}a,ans; ll n,t; void cheng(node a,node b,node &c) { for(int i=1;i<=n*9;i++) for(int j=1;j<=n*9;j++) { c.a[i][j]=0; for(int l=1;l<=n*9;l++) c.a[i][j]=(c.a[i][j]+(a.a[i][l]*b.a[l][j]))%mod; } } void qpow(node a,ll b) { while(b) { if(b&1) cheng(ans,a,ans); cheng(a,a,a); b>>=1; } } void add(int x,int y,int d) { if(d==0) return ; for(int i=1;i<d;i++) a.a[x*9+i][x*9+i+1]=1; // cout<<x*9+i<<" "<<x*9+i+1<<" "<<a.a[x*9+i][x*9+i+1]<<endl; a.a[x*9+d][y*9+1]=1; } int main() { int d; cin>>n>>t; for(int i=0;i<n;i++) for(int j=0;j<n;j++) { scanf("%1d",&d); //cout<<d<<" "; add(i,j,d); } ans=a; qpow(a,t-1); // for(int i=1;i<=(n-1)*9+1;i++) // { // for(int j=1;j<=(n-1)*9+1;j++) // cout<<ans.a[i][j]<<" "; // cout<<endl; // } cout<<ans.a[0*9+1][(n-1)*9+1]; }
Zeit und Raum trennen dich und mich.时空将你我分开。