正题
题目链接:https://www.luogu.org/problemnew/show/P2579
题目大意
一张无向图,一个起点一个终点。
有食人鱼,在若干个点之间有周期的移动,周期为222或333或444个点为循环。
然后要求从起点到终点走kkk步且不碰到食人鱼的方案数。
解题思路
因为食人鱼的周期为222或333或444,所以显然所有食人鱼的周期为lcm(2,3,4)=12lcm(2,3,4)=12lcm(2,3,4)=12一个循环。
然后kkk很大显然矩阵乘法。
转移矩阵G(k)G(k)G(k)中[i,j][i,j][i,j]表示在第kkk个时刻是否可以从iii移动到jjj。需要考虑连边和食人鱼具体分析。
构建好转移矩阵后G(k)G(k)G(k)我们开始转移,我们发现如果不考虑快速幂转移那么
Ans=G(1)∗G(2)∗G(3)...∗G(12)∗G(1)∗G(2)...∗G(k%12)Ans=G(1)*G(2)*G(3)...*G(12)*G(1)*G(2)...*G(k\%12)Ans=G(1)∗G(2)∗G(3)...∗G(12)∗G(1)∗G(2)...∗G(k%12)
中间有⌊k12⌋\lfloor \frac{k}{12}\rfloor⌊12k⌋个G(1)∗G(2)∗G(3)∗...G(12)G(1)*G(2)*G(3)*...G(12)G(1)∗G(2)∗G(3)∗...G(12)
那么我们让Gsum=G(1)∗G(2)∗G(3)...∗G(12)Gsum=G(1)*G(2)*G(3)...*G(12)Gsum=G(1)∗G(2)∗G(3)...∗G(12)
然后十分显然
Ans=Gsum⌊k12⌋∗∏i=1k%12G(i)Ans=Gsum^{\lfloor \frac{k}{12}\rfloor}*\prod_{i=1}^{k\%12}G(i)Ans=Gsum⌊12k⌋∗i=1∏k%12G(i)
然后用AnsAnsAns矩阵计算答案即可。
codecodecode
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int Size=60,T=12,XJQ=10000;
struct matrix{int a[Size][Size];
}ans,f[T];
int n,m,s,e,k,Nfish;
matrix operator *(matrix a,matrix b)
{matrix c;memset(c.a,0,sizeof(c.a));for(int i=0;i<Size;i++)for(int j=0;j<Size;j++)for(int k=0;k<Size;k++)(c.a[i][j]+=a.a[i][k]*b.a[k][j]%XJQ)%=XJQ;return c;
}
void power(int b)
{matrix F=f[0];for(int i=1;i<T;i++)F=F*f[i];while(b){if(b&1) ans=ans*F;F=F*F;b>>=1;}
}
int main()
{scanf("%d%d%d%d%d",&n,&m,&s,&e,&k);for(int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);for(int i=0;i<T;i++)f[i].a[x][y]=f[i].a[y][x]=1;}scanf("%d",&Nfish);for(int i=1;i<=Nfish;i++){int op,x,last;scanf("%d",&op);for(int j=0;j<op;j++){scanf("%d",&x);for(int k=j;k<T;k+=op){int now=k-1;if(now<0) now=T-1; for(int i=0;i<n;i++)f[now].a[i][x]=0;}}}ans.a[0][s]=1;power(k/T);for(int i=0;i<k%T;i++)ans=ans*f[i];printf("%d",ans.a[0][e]);
}