【P2579】【ZJTSC05】沼泽鳄鱼

链接:

题目

题目大意:

给定一个有 \(n\) 个点的无向图。Jayun 从点 \(s\)\(k\) 步到 \(e\),但是还有一些食 Jayun 魔在周期性地在一些点间运动,如果周期为 \(T\),则时间 \(i\)\(i+T\) 食 Jayun 魔位于同一个点。所以为了让 Jayun 不被吃掉,要在一些时刻避开必要的点。求出有多少种不同的合法路径。

正文:

如果没有食 Jayun 魔,可以直接用邻接矩阵快速幂 \(k\) 次就行了。

那么现在考虑有食 Jayun 魔的情况。设 \(G_i\) 表示时刻 \(i\) 去掉有食 Jayun 魔的点后的图。那么答案就是:

\[\prod_{i=1}^{K}G_i \]

又发现 \(2\leq T\leq4\),所以经过 \(\text{lcm}(2,3,4)=12\) 个时刻过后,图一定会变成原来的转移矩阵。通过这个性质就能得到:

\[\prod_{i=1}^{K}G_i=\left(\prod_{i=1}^{12}G_i\right)^{\lfloor\frac{K}{12}\rfloor}\cdot\prod_{i=1}^{k\bmod 12}G_i \]

这样就能 \(O(n^3\log K)\) 解决此题了。

代码:

struct matrix
{
	ll mat[N][N];
	int n, m;
	matrix(){memset(mat, 0, sizeof mat);}
	inline ll* operator [] (int b) { return mat[b];}
}stp[13], Ans;

inline matrix operator*(matrix &a, matrix &b)
{
	matrix c; c.n = a.n, c.m = b.m;
	for (int i = 1; i <= a.n; i++)
		for (int j = 1; j <= b.m; j++)
			for (int k = 1; k <= a.m; k++)
				c[i][j] = (c[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
	return c;
}

matrix qpow(matrix stp, ll b)
{
	matrix ans; ans.n = ans.m = stp.n;
	for (int i = 1; i <= ans.n; i++)
			ans[i][i] = 1;
	for (; b; b >>= 1)
	{
		if(b & 1) ans = ans * stp; 
		stp = stp * stp;
	}
	return ans;
}

int n, m, s, e, k, t;
int w[10];

int main()
{
	scanf ("%d%d%d%d%d", &n, &m, &s, &e, &k); 
	s++, e++;
	for (int i = 1; i <= m; i++)
	{
		int u, v;
		scanf ("%d%d", &u, &v);
		u++, v++;
		for (int j = 1; j <= 12; j++)
			stp[j][u][v] = stp[j][v][u] = 1, 
			stp[j].n = stp[j].m = n;
	}
	for (scanf ("%d", &t); t--; )
	{
		int nfish;
		scanf ("%d", &nfish);
		for (int i = 1; i <= nfish; i++)
			scanf ("%d", &w[i]), w[i]++;
		for (int i = 1; i <= n; i++)
			for (int j = 0; j <= 12; j++)
				stp[j][i][w[j % nfish + 1]] = 0;
	}
	Ans.n = Ans.m = n;
	for (int i = 1; i <= Ans.n; i++)
			Ans[i][i] = 1;
	for (int i = 1; i <= 12; i++)
		Ans = Ans * stp[i];
	Ans = qpow(Ans, k / 12);
	for (int i = 1; i <= k % 12; i++)
		Ans = Ans * stp[i];
	printf ("%d\n", Ans[s][e]);
	return 0;
}
posted @ 2020-12-26 09:38  Jayun  阅读(77)  评论(0编辑  收藏  举报