[ZJOI2004]沼澤鱷魚(矩陣乘法)

[ZJOI2004]沼澤鱷魚

時間限制:1 s   內存限制:256 MB

【題目描述】

潘塔納爾沼澤地號稱世界上最大的一塊溼地,它地位於巴西中部馬託格羅索州的南部地區。每當雨季來臨,這裏碧波盪漾、生機盎然,引來不少遊客。

爲了讓遊玩更有情趣,人們在池塘的中央建設了幾座石墩和石橋,每座石橋連接着兩座石墩,且每兩座石墩之間至多隻有一座石橋。這個景點造好之後一直沒敢對外開放,原因是池塘裏有不少危險的食人魚。

豆豆先生酷愛冒險,他一聽說這個消息,立馬趕到了池塘,想做第一個在橋上旅遊的人。雖說豆豆愛冒險,但也不敢拿自己的性命開玩笑,於是他開始了仔細的實地勘察,並得到了一些驚人的結論:食人魚的行進路線有周期性,這個週期只可能是2,3或者4個單位時間。每個單位時間裏,食人魚可以從一個石墩游到另一個石墩。每到一個石墩,如果上面有人它就會實施攻擊,否則繼續它的週期運動。如果沒有到石墩,它是不會攻擊人的。

藉助先進的儀器,豆豆很快就摸清了所有食人魚的運動規律,他要開始設計自己的行動路線了。每個單位時間裏,他只可以沿着石橋從一個石墩走到另一個石墩,而不可以停在某座石墩上不動,因爲站着不動還會有其它危險。如果豆豆和某條食人魚在同一時刻到達了某座石墩,就會遭到食人魚的襲擊,他當然不希望發生這樣的事情。

現在豆豆已經選好了兩座石墩Start和End,他想從Start出發,經過K個單位時間後恰好站在石墩End上。假設石墩可以重複經過(包括Start和End),他想請你幫忙算算,這樣的路線共有多少種(當然不能遭到食人魚的攻擊)

【輸入格式】

輸入文件共M + 2 + NFish行。

第一行包含五個正整數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的餘數就行了。

【樣例輸入】

6 8 1 5 30 22 11 00 55 11 44 33 513 0 5 1

【樣例輸出】

2

【提示】

1≤N≤50

1≤K≤2,000,000,000

1≤NFish≤20

T=2,3,4

【來源】

ZJTSC2005


假如沒有食人魚的話就是裸的矩陣乘了(若A,B聯通,就將s[A][B]賦值爲1,然後快速冪求方案數)。

我們可以發現,T只能是2,3,4,所以我們可以以他們的最小公倍數12爲一個週期,前12個暴力處理,中間部分將每12個看做一個矩陣快速冪,最後不足12個的暴力處理。

對食人魚的處理就是將對應時間的矩陣裏它出現的地點對應的的行和列清空,代表沒有從這個點走和來這個點的可行方案。

代碼:

#include<cstdio>
#include<iostream>
#include<cstring>
#define maxn 54
#define maxx 22
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
inline int read()
{   char c=getchar();int x=0,y=1;
	while(c<'0'||c>'9'){if(c=='-') y=-1;c=getchar();}
	while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x*y;
}
const int ki=10000;
int n,m,q,st,ed,K,num[maxx],rote[maxx][6];
struct matrix
{	int s[maxn][maxn];
	void cl(){mem(s,0);}
	matrix(){cl();}
	void init(){cl();for(int i=0;i<n;i++) s[i][i]=1;}
	void mt(int x,int y)
	{	if(y==-1) for(int i=0;i<n;i++) s[x][i]=0;
		if(x==-1) for(int i=0;i<n;i++) s[i][y]=0;
	}
	friend matrix operator * (matrix x,matrix y)
	{	matrix z;
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				for(int k=0;k<n;k++)
				{	int tmp=(x.s[i][k]*y.s[k][j])%ki;
					z.s[i][j]=(z.s[i][j]+tmp)%ki;
				}
		return z;
	}
}A[14],B,ans,dis;
int main()
{   freopen("swamp.in","r",stdin);
	freopen("swamp.out","w",stdout);
	n=read();m=read();st=read();ed=read();K=read();
	int x,y;
	for(int i=1;i<=m;i++) x=read(),y=read(),dis.s[x][y]=dis.s[y][x]=1;
	q=read();
	for(int i=1;i<=q;i++)
	{	num[i]=read();
		for(int j=1;j<=num[i];j++) rote[i][j]=read();
	}
	for(int i=1;i<=12;i++)
	{	A[i]=dis;
		for(int j=1;j<=q;j++)
		{	int tmp=(i-1)%num[j]+1,t2=(tmp==num[j])?rote[j][1]:rote[j][tmp+1];
			A[i].mt(rote[j][tmp],-1);A[i].mt(-1,t2);
		}
	}
	B.init();ans.init();
	for(int i=1;i<=12;i++)
		B=B*A[i];
	int edg=K/12;
	for(;edg;edg>>=1,B=B*B)
		if(edg&1) ans=ans*B;
	edg=K%12;
	for(int i=1;i<=edg;i++)
		ans=ans*A[i];
	printf("%d",ans.s[st][ed]);
	return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章