洛谷P2579 [ZJOI2005]沼泽鳄鱼(矩阵快速幂,周期)
例题:现在豆豆已经选好了两座石墩Start和End,他想从Start出发,经过K个单位时间后恰好站在石墩End上。假设石墩可以重复经过(包括Start和End),他想请你帮忙算算,这样的路线共有多少种(当然不能遭到食人鱼的攻击)。
输入格式:第一行包含五个正整数N,M,Start,End和K,分别表示石墩数目、石桥数目、Start石墩和End石墩的编号和一条路线所需的单位时间。石墩用0到N–1的整数编号。
第2到M + 1行,给出石桥的相关信息。每行两个整数x和y,0 ≤ x, y ≤ N–1,表示这座石桥连接着编号为x和y的两座石墩。
第M + 2行是一个整数NFish,表示食人鱼的数目。
第M + 3到M + 2 + NFish行,每行给出一条食人鱼的相关信息。每行的第一个整数是T,T = 2,3或4,表示食人鱼的运动周期。接下来有T个数,表示一个周期内食人鱼的行进路线。
如果T=2,接下来有2个数P0和P1,食人鱼从P0到P1,从P1到P0,……;
如果T=3,接下来有3个数P0,P1和P2,食人鱼从P0到P1,从P1到P2,从P2到P0,……;
如果T=4,接下来有4个数P0,P1,P2和P3,食人鱼从P0到P1,从P1到P2,从P2到P3,从P3到P0,……。
豆豆出发的时候所有食人鱼都在自己路线上的P0位置,请放心,这个位置不会是Start石墩。
输出格式:输出路线的种数,因为这个数可能很大,你只要输出该数除以10000的余数就行了。
#include<cstdio> #include<cstring> const int mod = 10000; int x,y,n,m,k,s,t,fish; int res[30][5],tt[30]; struct Node{ int a[60][60]; Node operator *(const Node &x)const{ Node ans; memset(ans.a,0,sizeof(a)); for(int i = 0; i < n; ++i) for(int t = 0; t < n; ++t) for(int k = 0; k < n; ++k) ans.a[i][t] = (ans.a[i][t]+a[i][k]*x.a[k][t]) % mod; return ans; } }h[15],bb,base,ans; void quick_pow(int k){ while(k){ if(k&1) ans = ans*base; base = base*base; k >>= 1; } } int main(){ scanf("%d%d%d%d%d",&n,&m,&s,&t,&k); for(int i = 1; i <= m; ++i){ scanf("%d%d",&x,&y); bb.a[x][y] = bb.a[y][x] = 1; } scanf("%d",&fish); for(int i = 0; i < fish; ++i){ scanf("%d",&tt[i]); for(int t = 0; t < tt[i]; ++t) scanf("%d",&res[i][t]); } for(int i = 0; i < 12; ++i){ h[i] = bb; for(int t = 0; t < fish; ++t) for(int k = 0; k < n; ++k) h[i].a[k][res[t][(i+1)%tt[t]]] = 0; } base = h[0]; for(int i = 1; i < 12; ++i) base = base*h[i]; for(int i = 0; i < n; ++i) ans.a[i][i] = 1; quick_pow(k/12); for(int i = 1; i <= k%12; ++i) ans = ans*h[i-1]; printf("%d",ans.a[s][t]); return 0; }
你只有十分努力,才能看上去毫不费力。