【JZOJ3847】都市环游【dp】【矩阵乘法】
题目大意:
题目链接:https://jzoj.net/senior/#main/show/3847
因为SJY干的奇怪事情过多,SJY收到了休假的通知,于是他准备在都市间来回旅游。SJY有一辆车子,一开始行驶性能为0,每过1时间行驶性能就会提升1点。每个城市的道路都有性能要求。SJY一共有t时间休息,一开始他位于1号城市(保证1号城市道路要求为0),他希望在n号城市结束旅程。每次穿过一条城市间的路会花费1时间,当然他也可以停留在一个城市不动而花费1时间。当且仅当车子的行驶性能大于等于一个城市,我们才能到达那里。SJY希望知道,旅游的方案模10086后的答案。(只要在某一时刻通过的道路存在一条不相同,就算不同的方案)
思路:
如果没有性能的要求,那么这道题就是一道矩阵乘法的裸题。
但是有性能的要求,而矩阵乘法中是没办法判断的。
观察到这道题,所以当之后就不用再考虑性能的问题了。
所以我们可以用推出前个单位时间到达每一个点的方案数,然后矩阵乘法次即可。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=110,MOD=10086;
int n,m,t,h[N],g[N][N];
struct matrix
{
int a[N][N];
}f,a;
matrix operator *(matrix a,matrix b)
{
matrix c;
memset(c.a,0,sizeof(c.a));
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
for (int k=1;k<=n;k++)
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%MOD;
return c;
}
void power(int k)
{
for (;k;k>>=1,a=a*a)
if (k&1) f=f*a;
}
int main()
{
scanf("%d%d%d",&n,&m,&t);
for (int i=1;i<=n;i++)
scanf("%d",&h[i]);
for (int i=1,x,y;i<=m;i++)
{
scanf("%d%d",&x,&y);
a.a[x][y]++;
}
for (int i=1;i<=n;i++)
a.a[i][i]=1;
g[1][0]=1;
for (int i=1;i<=70;i++)
for (int j=1;j<=n;j++)
if (h[j]<=i)
{
for (int k=1;k<=n;k++)
if (a.a[k][j])
g[j][i]=(g[j][i]+g[k][i-1]*a.a[k][j])%MOD;
}
if (t<=70) return !printf("%d",g[n][t]);
for (int i=1;i<=n;i++)
f.a[1][i]=g[i][70];
power(t-70);
printf("%d",f.a[1][n]);
return 0;
}