Time Limits: 1000 ms Memory Limits: 65536 KB Detailed Limits
Description
windy在有向图中迷路了。
该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。
现在给出该有向图,你能告诉windy总共有多少种不同的路径吗?
注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。
Input
第一行包含两个整数,N T。
接下来有 N 行,每行一个长度为 N 的字符串。
第i行第j列为'0'表示从节点i到节点j没有边。
为'1'到'9'表示从节点i到节点j需要耗费的时间。
Output
输出一个整数,可能的路径数,这个数可能很大,只需输出这个数除以2009的余数。
Sample Input
2 2 11 00
Sample Output
1
Data Constraint
Hint
100%的数据,满足 2 <= N <= 10 ; 1 <= T <= 1000000000 。
Source / Author: 四川2009省选第2试第3题
题解:
N那么鬼死小 , T那么鬼死大,肯定是矩乘。
先想出我们的朴素dp , f[k][i][j]表示从i到走到j点刚好到了k时刻的方案数。
因为T很大 , 想到用f乘上(某转移矩阵M) T次 , 这样才不会炸时间。
M是什么呢?
假如边权是1的话 , 对于边 i -> j , M[i][j]=1表示(到当前时间点)i点能走到j点的方案数为1.
然后直接快速幂T次即可。
但是边权不一定为1啊 , 这样构造显然是不行的。既然这样 , 我们就把一个点拆成9个点(边权从1到9) ,先把所有(i,k)向(i,k+1)连一条边,对于一条边i->j边权为k , 我们将(i , k) 和(j , 1)连一条1的边 , 也就是M[(i,k)][(j,1)]=1 。
如图:
:我们钦定(i,1)为i的起始点 , 先把所有(i,k)向(i,k+1)连一条边。
:对于一条边i->j边权为k , 我们将(i , k) 和(j , 1)连一条1的边 , 也就是M[(i,k)][(j,1)]=1 。
(如图是当k等于3的情况)
这样构造的话 从(i,1)到(i,k)一共走了(k-1)条边 , 还有一条从(i,k)到(j,1)的边,一共k条。
就是说我们把权值k拆成了k段权值为1的来做。
至于矩阵乘法的内部原理 , 不用多解释 , 自己手玩样例即可食用。
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define mcy(a,b) memcpy(a,b,sizeof(a))
#define ll long long
#define inf 2000000000
#define N 110
#define maxn 150
#define mod 2009
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
int n,T ,tmp;
char s[N];
int a[N][N] ;
struct matrix
{
int a[maxn][maxn];
int L , R;
matrix() {mem(a,0);L = R =0;}
void init(int l,int r) {mem(a,0);L = l ; R = r;}
void print()
{
for(int i=1;i<=L;i++,puts(""))
for(int j=1;j<=R;j++) printf("%d " , a[i][j]);
}
void read()
{
for(int i=1;i<=L;i++)
{
for(int j=1;j<=R;j++) scanf("%d" , &a[i][j]);
}
}
}f , c;
//g i , j i状态转移到j状态的期望
__attribute((optimize(3)))
matrix mul(matrix a,matrix b)
{
matrix c;
c . init(a.L , b.R);
for(int i=1;i<=a.L;i++)
for(int j=1;j<=b.L;j++)
for(int k=1;k<=a.R;k++) (c.a[i][j] += a.a[i][k] * b.a[k][j])%=mod;
return c;
}
__attribute((optimize(3)))
matrix operator * (matrix a,matrix b)
{return mul(a,b);}
__attribute((optimize(3)))
matrix sqr(matrix x)
{return x*x;}
__attribute((optimize(3)))
matrix power(matrix x , int p)
{
matrix ans = c;
while(p)
{
if(p&1) ans = ans * x;
x = sqr(x);
p>>=1;
}
return ans;
}
__attribute((optimize(3)))
void read()
{
for(int i=1;i<=n;i++)
{
scanf("%s\n",s+1);
for(int j=1;j<=n;j++)
a[i][j] = s[j] - '0' ;
}
}
int st=0,id[N][10];
__attribute((optimize(3)))
void init()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=9;j++)++st , id[i][j] = st;
f.init(st,st);
for(int i=1;i<=n;i++)
for(int j=1;j<9;j++) f.a[id[i][j]][id[i][j+1]] = 1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) if(tmp = a[i][j]) f.a[id[i][tmp]][id[j][1]] = 1;
c.init(st,st);
for(int i=1;i<=st;i++)c.a[i][i]=1;
f.print();
}
matrix ans;
__attribute((optimize(3)))
void work()
{
f = power(f,T);
ans = f;
}
__attribute((optimize(3)))
int main()
{
open("way");
scanf("%d%d\n",&n,&T);
read();
init();
work();
printf("%d",ans . a[id[1][1]][id[n][1]]);
return 0;
}
O(log T * statetot ^ 3)