一张无向图,有 n n n个点, m m m条无向边
规定起点为 S S S,终点为 T T T
每个一个单位时间只能移动一次
一些食人鱼作周期运动,人在任意单位时间不能碰到食人鱼
要求经过 K K K个单位时间后恰好到达 T T T
问合法路径方案总数,这个结果对 1 e 4 1e4 1e4取模
1 ≤ 食 人 鱼 个 数 ≤ 20 1 ≤ 食人鱼个数 ≤ 20 1≤食人鱼个数≤20
2 ≤ 周 期 运 动 长 度 ≤ 4 2≤周期运动长度≤4 2≤周期运动长度≤4
K < = 2 ∗ 1 0 9 K<=2∗10^9 K<=2∗109
考虑没有食人鱼的情况,
设 f k , i , j f_{k,i,j} fk,i,j表示走了 k k k步,位置 i i i到 j j j的路径方案总数
显然一开始 f 1 , i , j = 1 ( i , j 连 通 ) f_{1,i,j}=1(i,j连通) f1,i,j=1(i,j连通)否则 f 1 , i , j = 0 f_{1,i,j}=0 f1,i,j=0
然后每次转移即 f k , i , j = Σ l = 1 n f k − 1 , i , l ∗ f 1 , l , j f_{k,i,j}=Σ_{l=1}^{n}f_{k-1,i,l}*f_{1,l,j} fk,i,j=Σl=1nfk−1,i,l∗f1,l,j
这一看不就是矩阵乘法吗,
显然最后的答案得到的矩阵为 f 1 K {f_1}^K f1K,
设最后得到的矩阵为 C C C,则 C S , T C_{S,T} CS,T即为所求
此时对于存在食人鱼的情况,
观察到周期长度只有 2 , 3 , 4 2,3,4 2,3,4, l c m ( 2 , 3 , 4 ) = 12 lcm(2,3,4)=12 lcm(2,3,4)=12,
那么我们就可以以 12 12 12为一个周期去搞定每个单位时间图的合法连通情况,
即设 U s e T i m e k UseTime_k UseTimek表示单位时间为 L ∗ 12 + k L*12+k L∗12+k时图的合法连通情况 ( L ∈ Z ) (L∈Z) (L∈Z)
我们发现如果一个食人鱼在单位时间 L ∗ 12 + k + 1 L*12+k+1 L∗12+k+1会出现在位置 x x x,那么这个单位时间 L ∗ 12 + k L*12+k L∗12+k所有连向 x x x的边都应该断掉,因为必定不合法,然后综合一下原图的连通情况即可求得 U s e T i m e k UseTime_k UseTimek
那么答案显然就是各个单位时间的图的连通情况的乘积
为了优化时间,我们可以设 S u m = ∏ i = 1 12 U s e T i m e i Sum=\prod_{i=1}^{12} UseTime_i Sum=∏i=112UseTimei
然后最后的答案矩阵 A n s w e r Answer Answer即为
S u m ⌊ K / 12 ⌋ ∗ ∏ i = 1 K m o d 12 U s e T i m e i Sum^{\left \lfloor K/12 \right \rfloor}*\prod_{i=1}^{Kmod12}UseTime_i Sum⌊K/12⌋∗∏i=1Kmod12UseTimei
前面矩阵快速幂,后面暴力算即可,注意矩阵乘法不满足交换律,要顺次算
最后合法方案总数就是 A n s w e r S , T Answer_{S,T} AnswerS,T
#include
#include
#include
#include
#include
#include
#include
#define modn 10000
#define N 55
using namespace std;
typedef long long ll;
struct Matrix { int Num[N][N]; };
Matrix UseTime[15], AwekTime, Total, C, A;
int KDA[N], n, m, S, T, K, NFish;
void mul(Matrix AA, Matrix BB, int opt)
{
memset(C.Num, 0, sizeof(C.Num));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
C.Num[i][j] = (C.Num[i][j] + AA.Num[i][k] * BB.Num[k][j]) % modn;
if (opt == 1) memcpy(AwekTime.Num, C.Num, sizeof(C.Num));
if (opt == 2) memcpy(Total.Num, C.Num, sizeof(C.Num));
}
void ksm(int x)
{
for (int i = 1; i <= n; i++) AwekTime.Num[i][i] = 1;
for (int i = 1; i <= 12; i++) mul(AwekTime, UseTime[i], 1);
for (; x; x >>= 1)
{
if (x & 1) mul(Total, AwekTime, 2);
mul(AwekTime, AwekTime, 1);
}
}
int main()
{
scanf("%d %d %d %d %d", &n, &m, &S, &T, &K);
for (int i = 1; i <= m; i++)
{
int x, y; scanf("%d %d", &x, &y);
A.Num[x + 1][y + 1] = A.Num[y + 1][x + 1] = 1;
}
for (int i = 1; i <= 12; i++)
memcpy(UseTime[i].Num, A.Num, sizeof(A.Num));
scanf("%d", &NFish);
while (NFish--)
{
int yzh; scanf("%d", &yzh);
for (int i = 1; i <= yzh; i++) scanf("%d", &KDA[i]);
int ID = 1;
for (int i = 1; i <= 12; i++)
{
++ID; if (ID == yzh + 1) ID = 1;
for (int j = 1; j <= n; j++) UseTime[i].Num[j][KDA[ID] + 1] = 0;
}
}
for (int i = 1; i <= n; i++) Total.Num[i][i] = 1;
ksm(K / 12);
for (int i = 1; i <= K % 12; i++) mul(Total, UseTime[i], 2);
printf("%d\n", Total.Num[S + 1][T + 1]);
return 0;
}