题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1898
思路 : 因为是中文题,题意就不过多描述了。食人鱼的活动周期分别是2、3或4,这样可以考虑所有的食人鱼的活动情况一定是最小以12为周期的,这样我们就构造12个矩阵,a[ i ].m[ x ][ y ]每个矩阵表示在第 i 时刻,从第 x 个石墩到第 y 个石墩能不能走,这样将这十二个矩阵相乘,得到第十三个矩阵a[0],对于 K/12 的部分,我们可以直接求 a[0]^(k/12) 得到,对于 K%12 的部分暴力乘起来就好。
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 10000
int n,m,S,T,K,q;
int pos[5];
struct node
{
int m[55][55];
}a[13],b,ans,td;
node mul(node a,node b)
{
node c;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
c.m[i][j] = 0;
for(int k=0;k<n;k++)
c.m[i][j] = (c.m[i][j] + a.m[i][k]*b.m[k][j]) % mod;
}
return c;
}
node ksm(node aa,int k)
{
node ans = td;
while(k)
{
if(k & 1)
ans = mul(ans,aa);
aa = mul(aa,aa);
k >>= 1;
}
return ans;
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&S,&T,&K);
for(int i=0;i<n;i++) td.m[i][i] = 1;
int x,y;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
for(int j=1;j<=12;j++)
{
a[j].m[x][y]++;
a[j].m[y][x]++;
}
}
a[0] = td;
scanf("%d",&q);
while(q--)
{
int k;
scanf("%d",&k);
for(int i=1;i<=k;i++)
scanf("%d",&pos[i]);
if(pos[1] == S || pos[K%k+1] == T)
{
printf("0\n");
return 0;
}
for(int j=0;j<k;j++) pos[j] = pos[j+1];
for(int i=1;i<=12;i++)
{
int x = (i-1)%k;
for(int j = 0;j<n;j++)
a[i].m[pos[x]][j] = 0;
}
}
for(int i=1;i<=12;i++)
a[0] = mul(a[0],a[i]);
a[0] = ksm(a[0],K/12);
K %= 12;
b.m[0][S] = 1;
b = mul(b,a[0]);
for(int i=1;i<=K;i++)
b = mul(b,a[i]);
printf("%d\n",b.m[0][T]);
return 0;
}