【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后的答案。(只要在某一时刻通过的道路存在一条不相同,就算不同的方案)


思路:

如果没有性能的要求,那么这道题就是一道矩阵乘法的裸题。
但是有性能的要求,而矩阵乘法中是没办法判断的。
观察到这道题hi70h_i\leq 70,所以当t>70t>70之后就不用再考虑性能的问题了。
所以我们可以用dpdp推出前7070个单位时间到达每一个点的方案数,然后矩阵乘法t70t-70次即可。


代码:

#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;
}
posted @ 2019-11-07 18:31  全OI最菜  阅读(124)  评论(0编辑  收藏  举报