[Jzoj] 1036.【SCOI2009】迷路

题目大意

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

题目解析

由于这道题的 TTT 很大,线性算法是过不了的,所以我们考虑矩阵乘法。
这道题图中的边权为 1 91~91 9,比较小,所以考虑拆点,为了方便表示,把编号为 iii的点拆为 i∗10+1 i∗10+9i*10+1~i*10+9i10+1 i10+9 一共 999 个节点。如果 iiijjj 有一条权值为 kkk 的路径,那么就把矩阵中[i∗10+k,j∗10+1][i*10+k,j*10+1][i10+k,j10+1]的值设为 1,相当于先从 i∗10+1→i∗10+ki*10+1→i*10+ki10+1i10+k 走过 k−1k-1k1条长度为 111 的路径,再在 i∗10+k→j∗10+1i*10+k→j*10+1i10+kj10+1 走过 111 条长度为 111 的路径,总长度为kkk,跑一遍快速幂,[1∗10+1][n∗10+1][1*10+1][n*10+1][110+1][n10+1]的值即是方案总数。

代码

#include<bits/stdc++.h>
#define N 105
#define M 2009
using namespace std;
int n,t,an;
int m[N][N],tmp[N][N],ans[N][N];
char c;
void mul(int a[N][N],int b[N][N])
{
	memset(tmp,0,sizeof(tmp));
	for(int i=0;i<an;i++)
	 for(int j=0;j<an;j++)
	  for(int k=0;k<an;k++)
	   tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%M;
	memcpy(a,tmp,sizeof(tmp));
}
void qpow()
{
	for(int i=0;i<an;i++) ans[i][i]=1;
	while(t)
	{
	  if(t&1) mul(ans,m);
	  mul(m,m);
	  t>>=1;
	}
}
int main()
{
	cin>>n>>t;
	an=n*9;
	for(int i=0;i<n;i++)
	{
	  for(int j=0;j<8;j++)
	   m[i*9+j][i*9+j+1]=1;
	  for(int j=0,num;j<n;j++)
	  {
	  	cin>>c;
	  	num=c-'0';
	  	if(num) m[i*9+num-1][j*9]=1;
	  }
	}
	qpow();
	cout<<ans[0][(n-1)*9];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值