1. 程式人生 > >【bzoj4887】[Tjoi2017]可樂 矩陣乘法

【bzoj4887】[Tjoi2017]可樂 矩陣乘法

三種 行為 pos per bsp 復雜 std () 乘法

題目描述

加裏敦星球的人們特別喜歡喝可樂。因而,他們的敵對星球研發出了一個可樂機器人,並且放在了加裏敦星球的1號城市上。這個可樂機器人有三種行為:停在原地,去下一個相鄰的 城市,自爆。它每一秒都會隨機觸發一種行為。現在給出加裏敦星球城市圖,在第0秒時可樂機器人在1號城市,問經過了t秒,可樂機器人的行為方案數是多少?

輸入

第一行輸入兩個正整數N,M表示城市個數,M表示道路個數。(1≤N≤30,0≤M≤100) 接下來M行輸入u,v表示u,v之間有一條道路。 (1≤u,v≤n)保證兩座城市之間只有一條路相連。 最後輸入時間t。1<t≤10^6

輸出

輸出可樂機器人的行為方案數,答案可能很大,請輸出對2017取模後的結果。

樣例輸入

3 2
1 2
2 3
2

樣例輸出

8


題解

矩陣乘法

傻逼題,顯然鄰接矩陣自乘。對於停留,每個點連一個自環;對於自爆,每個點向虛擬節點連邊,虛擬節點連自環。

矩陣的 $t$ 次冪的第一行的和即為答案。

時間復雜度 $O(n^3\log t)$

#include <cstdio>
#include <cstring>
int n;
struct data
{
	int v[35][35];
	data() {memset(v , 0 , sizeof(v));}
	int *operator[](int a) {return v[a];}
	data operator*(data &a)
	{
		data ans;
		int i , j , k;
		for(i = 0 ; i <= n ; i ++ )
			for(k = 0 ; k <= n ; k ++ )
				for(j = 0 ; j <= n ; j ++ )
					ans[i][j] = (ans[i][j] + v[i][k] * a[k][j]) % 2017;
		return ans;
	}
}A;
data pow(data x , int y)
{
	data ans;
	int i;
	for(i = 0 ; i <= n ; i ++ ) ans[i][i] = 1;
	while(y)
	{
		if(y & 1) ans = ans * x;
		x = x * x , y >>= 1;
	}
	return ans;
}
int main()
{
	int m , k , i , x , y , ans = 0;
	scanf("%d%d" , &n , &m);
	for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &x , &y) , A[x][y] = A[y][x] = 1;
	for(i = 1 ; i <= n ; i ++ ) A[i][i] = A[i][0] = 1;
	A[0][0] = 1;
	scanf("%d" , &k) , A = pow(A , k);
	for(i = 0 ; i <= n ; i ++ ) ans = (ans + A[1][i]) % 2017;
	printf("%d\n" , ans);
	return 0;
}

【bzoj4887】[Tjoi2017]可樂 矩陣乘法