BZOJ 入门OJ 2007: [Noip模拟题]都市环游

题目链接

题目大意

有一辆车子,一开始行驶性能为0,每过1时间行驶性能就会提升1点。每个城市的道路都有性能要求。一开始位于1号城市,可以选择穿过一条城市间的路,也可以选择停留在一个城市不动,两个选择都花费1时间。只有车子的行驶性能大于等于一个城市时,车子才能到达该城市。求时间t时,位于城市n的路线方案数模10086后的值。

数据范围

节点数\(n\)\(m \leq 70\)
边数\(m\)\(m \leq 5000\)
时间\(t\)\(t \leq 10000000\)
\(i\)个城市的性能要求\(h_i\)\(h_i \leq 70\)

分析

在开始有城市限制的时间内DP求方案数(已知\(h_i \leq 70\))。然后计算没有限制后,各城市之间可行路径的邻接矩阵。根据第70秒个城市方案数的结果计算第71秒各个城市之间路径的方案数。两矩阵相乘可以得到下一次的邻接矩阵。因此可以进行矩阵快速幂得到最终解。
复杂度\(O(70*m + n^3*log_2(t-70)) = O(n^3*log_2t)\)

算法

参考代码

#include <bits/stdc++.h>
using namespace std;
#define rg register

const int MAXN = 70 + 5;
const int MAXM = 5000 + 5;
const int MOD = 10086;

struct Matrix
{
	int n, m, x[MAXN][MAXN];   
	Matrix()
	{
		memset(x, 0, sizeof x);
	} 
	Matrix operator * (const Matrix a) 
	{
		Matrix y;
		y.n = a.n, y.m = a.m;
		for(rg int i = 0; i < n; ++i)
			for (rg int k = 0; k < m; ++k)
				if(x[i][k]) 
					for(rg int j = 0; j < a.m; ++j)
						(y.x[i][j] += x[i][k] * a.x[k][j]) %= MOD;
		return y;
	}
}M, N;

struct Edge
{
	int to, next;
}E[MAXM], E2[MAXM];

int n, m, t;
int A[MAXN];
int H[MAXN], H2[MAXN], cntE, cntE2;

inline void AddEdge(int u, int v)
{
	E[++cntE] = (Edge){v, H[u]};
	H[u] = cntE;
return ;
}

inline void AddEdge2(int u, int v)
{
	E2[++cntE2] = (Edge){v, H2[u]};
	H2[u] = cntE2;
return ;
}

void Input()
{
	scanf("%d%d%d", &n, &m, &t);
	++t;
	for(rg int i = 0; i < n; ++i)
		scanf("%d", &A[i]);
	for(rg int i = 0, a, b; i < m; ++i)
	{
		scanf("%d%d", &a, &b);
		AddEdge(a - 1, b - 1);
		AddEdge2(b - 1, a - 1);
	}
	return ;
}

int F[MAXN][MAXN];

void Dp()
{
	F[0][0] = 1;
	for(rg int i = 1; i < min(t + 1, 71); ++i)
	{
		for(rg int j = 0; j < n; ++j)
		{
			F[i][j] = F[i - 1][j];
			if(i <= A[j])
				continue;
			for(rg int e = H2[j]; e; e = E2[e].next)
				(F[i][j] += F[i - 1][E2[e].to]) %= MOD;
		}
	}
	if(t < 71)
	{
		printf("%d\n", F[t][n - 1]);
		exit(0);
	}
	return ;
}

void InitMatrix()
{
	M.n = M.m = N.n = N.m = n;
	for(rg int i = 0; i < n; ++i)
	{
		N.x[i][i] = 1;
		for(rg int j = H[i]; j; j = E[j].next) 
			++N.x[i][E[j].to];
	}
	for(rg int i = 0; i < n; ++i)
	{
		M.x[i][i] = F[70][i];
		for(rg int j = H[i]; j; j = E[j].next)
			(M.x[i][E[j].to] += F[70][i]) %= MOD;
	}
	return ;
}

void QuickPower(int times)
{ 
	for(; times; times >>= 1)
	{
		if(times & 1)
			M = M * N;
		N = N * N;
	}
	int ans = 0;
	for(rg int i = 0; i < n; ++i)
		(ans += M.x[i][n - 1]) %= MOD;
	printf("%d\n", ans);
	return ;
}

int main()
{
	Input();
	Dp();
	InitMatrix();
	QuickPower(t - 71);
	return 0;
} 
posted @ 2017-09-28 13:26  SkqLiao  阅读(175)  评论(0编辑  收藏  举报