【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;
}