洛谷 P4159 [SCOI2009]迷路

windy在有向图中迷路了。 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。

根据题意,可以写出转移方程

\[f_{i,j}=\sum f_{r,j-w[r]} \]

\(f_{i,j}\)表示第\(j\)时刻在第\(i\)个点时的方案数,\(r\)\(i\)的前驱,\(w[r]\)为距离

\(T\le 10^9\),所以肯定是不可行的,就要用到矩阵加速

如果对于上面那个转移方程是无法矩阵加速的

但是边权只有\(1…9\),我们可以把\(j\)分开表示,也就是把所有距离的情况都表示出来

那么对于上面的那个转移方程就有两种转移形式

  • 这个距离\(j\)不是真正的距离,那么\(f_{r,j}\)可以从\(f_{r,j-1}\)继承

  • 这个\(j\)是真正的距离,那么\(f_{r,j}\)\(f_{i,j}\)是有贡献的

代码和拆点一样= =

Code

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,t,d[500][500],s[500][500],b[500][500],p=2009;
char ch;
void jzc(int x[500][500],int y[500][500])
{
	for (int i=1;i<=n*9;i++)
		for (int j=1;j<=n*9;j++)
			for (int k=1;k<=n*9;k++)
				b[i][j]=(b[i][j]+x[i][k]*y[k][j]%p)%p;
	for (int i=1;i<=n*9;i++)
		for (int j=1;j<=n*9;j++)
			x[i][j]=b[i][j],b[i][j]=0;
}
int main()
{
	cin>>n>>t;
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=8;j++)     //第一个的继承关系
			d[i+j*n][i+(j-1)*n]=1;
		for (int j=1;j<=n;j++)
		{
			cin>>ch;
			d[i][j+n*((ch-'0')-1)]=1;   //真正的边
		}
	}
	for (int i=1;i<=n*9;i++)
		s[i][i]=1;
	while (t)
	{
		if (t&1)jzc(s,d);
		jzc(d,d);
		t>>=1;
	}
	cout<<s[1][n]<<endl;
	return 0;
}
posted @ 2020-06-08 20:10  eee_hoho  阅读(190)  评论(0编辑  收藏  举报