【矩阵乘法】沼泽鳄鱼

链接

SSL 2511

题目描述

一个池塘,一些鳄鱼,鳄鱼有周期( 2 ≤ 周 期 ≤ 4 2\leq周期\leq4 24)的运动路线,你要从某个点恰好走某个步数走到另一个点,然后你不能和任何一个鳄鱼同时存在于一个点上,问你有多少种走法。
方案数对 10000 取模。

样例输入

6 8 1 5 3
0 2
2 1
1 0
0 5
5 1
1 4
4 3
3 5
1
3 0 5 1

样例输出

2

思路

考虑怎么样去掉周期
周期有2,3,4,那就是长度为12的大周期

然后对于这个大周期,那就求出每个基础的矩阵,那对于每个时间,我们只需要把被鳄鱼占领的点去掉即可得到改动的矩阵

然后就先乘 k / 12 k / 12 k/12个大周期,然后再乘剩下的余数即可

代码

#include<algorithm> 
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long 

using namespace std;

const int mo = 10000;

struct matrix
{
    
    
	int n, m;
	int a[55][55];
}nor, ans, all, c, t[5005], E;

int n, m, s, e, k, num;
int P[5005][5005], T[5005];

matrix operator *(matrix a, matrix b)
{
    
    
	c.n = a.n;
	c.m = b.m;
	for(int i = 0; i < c.n; ++i)
	for(int j = 0; j < c.m; ++j)
		c.a[i][j] = 0;
	for(int k = 0; k < a.m; ++k)
		for(int i = 0; i < c.n; ++i)
			for(int j = 0; j < c.m; ++j)
				c.a[i][j] = (c.a[i][j] + (a.a[i][k] * b.a[k][j]) % mo) % mo;
	return c;
}

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);
		nor.a[x][y] = nor.a[y][x] = 1;
	}
	nor.n = n;
	nor.m = n;
	E.n = n;
	E.m = n;
	for (int i = 0; i < n; i++)
		E.a[i][i] = 1;
	all = E;
	ans = E;
	scanf("%d", &num);
	for(int i = 1; i <= num; ++i)
	{
    
    
		scanf("%d", &T[i]);
		for(int j = 0; j < T[i]; ++j)
			scanf("%d", &P[i][j]);
	}
	for(int i = 1; i <= 12; ++i)
	{
    
    
		t[i] = nor;
		for(int j = 1; j <= num; ++j)
		{
    
    
			int to = P[j][i % T[j]];
			for(int k = 0; k < n; ++k)
				 t[i].a[k][to] = 0;//标记被占领的位置
		}
		all = all * t[i];
	}//先乘出大周期矩阵
	int allt = k / 12;
	while(allt)
	{
    
    
		if(allt & 1) ans = ans * all;
		all = all * all;
		allt /= 2;
	}
	allt = k % 12;
	for(int i = 1; i <= allt; ++i)
		ans = ans * t[i];
	printf("%d", ans.a[s][e]);
}

猜你喜欢

转载自blog.csdn.net/LTH060226/article/details/111407433
今日推荐