[FJOI2018D1T3]城市路徑問題

Description

傑傑是魔法界的一名傳奇人物。他對魔法具有深刻的洞察力,驚人的領悟力,以及令人歎爲觀止的創造力。自從他從事魔法競賽以來,短短几年時間,就已經成爲世界公認的實力最強的魔法選手之一。更讓人驚歎的是,他幾乎沒有藉助外界力量,完全憑藉自己的努力達到了普通人難以企及的高度。在最近的世界魔法奧林匹克競賽上,他使用高超的魔法本領,一路過關斬將,在最後時刻一舉擊敗了前冠軍“旅行者”,獲得了魔法界最高的榮耀:女神獎盃!女神獎盃可不是一個普通的獎盃,她能夠幫傑傑實現一個願望。

傑傑本着實事求是的態度,審時度勢,向女神獎盃提出了自己的願望:想要一個女性朋友。

傑傑的願望實現了,可是女性朋友卻和他不在一個城市。傑傑想要知道:如果要到達女性朋友的所在城市,有多少種方案供他選擇?

傑傑所在的世界有 nn 個城市,從 11nn 進行編號。任意兩個城市都通過有向道路連接。

每個城市 uukk 個入點權:in[u][1],in[u][2]...in[u][k]in[u][1],in[u][2]...in[u][k],有 kk 個出點權:ou[u][1],ou[u][2]...ou[u][k]ou[u][1],ou[u][2]...ou[u][k]

對於任意兩個城市 (u,v)(u,v)uu 可以等於 vv),uuvv 的道路條數爲 (ou[u][1]in[v][1]+ou[u][2]in[v][2]+...+ou[u][k]in[v][k])(ou[u][1]*in[v][1]+ou[u][2]*in[v][2]+...+ou[u][k]*in[v][k]) 條。

傑傑有 mm 次詢問,每次詢問由三元組 (u,v,d)(u,v,d) 構成,詢問從 uu 城市通過不超過 dd 條道路到達 vv 城市的方案數。

爲了溫柔的傑傑和他的女性朋友的美好未來,幫助他解答這個問題吧。

input

第一行讀入兩個正整數 nnkk,含義如題所示。接下來 nn 行每行 2k2k 個整數,第 ii 行代表第 ii 個城市,前 kk 個整數代表 ii 號城市的出點權,後 kk 個整數代表i號城市的入點權:ou[i][1],ou[i][2],,ou[i][k],in[i][1],in[i][2],,in[i][k]ou[i][1],ou[i][2],…,ou[i][k],in[i][1],in[i][2],…,in[i][k]

接下來一個整數 mm,表示 mm 個詢問。

接下來 mm 行,每行三個整數: u,v,du,v,d,詢問從 uu 城市通過不超過 dd 條道路到達 vv 城市的方案數。

將每個方案所經過的道路,按順序寫成一個序列(序列可以爲空)。兩個方案不同,當且僅當他們的道路序列不完全相同。

output

對於每個詢問,輸出一個方案數。由於答案可能太大,輸出其除以 10000000071000000007 後的餘數。

Data

對於 40%40\% 的數據,n50,k20,m45n \le 50,k \le 20, m \le 45

對於另外 10%10\% 的數據,n1000,k=1,m45n \le 1000, k = 1, m \le 45

對於 100%100\% 的數據,n1000,k20,m50n \le 1000, k \le 20, m \le 50

Solution

很明顯的矩陣快速冪,發現如果是整個矩陣拿去搞的話 100031000^3 就爆炸了,考慮可以把轉移拆開,只有第一次和最後一次是 1000×201000\times20 的轉移,中間的都是 20×2020\times 20 的轉移,直接做就好了。

Code

#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <queue>
#include <set>
#include <stack>

#define R register
#define ll long long
#define db double
#define sqr(_x) (_x) * (_x)
#define Cmax(_a, _b) ((_a) < (_b) ? (_a) = (_b), 1 : 0)
#define Cmin(_a, _b) ((_a) > (_b) ? (_a) = (_b), 1 : 0)
#define Max(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define Min(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define Abs(_x) (_x < 0 ? (-(_x)) : (_x))

using namespace std;

namespace Dntcry
{
	inline int read()
	{
		R int a = 0, b = 1; R char c = getchar();
		for(; c < '0' || c > '9'; c = getchar()) (c == '-') ? b = -1 : 0;
		for(; c >= '0' && c <= '9'; c = getchar()) a = (a << 1) + (a << 3) + c - '0';
		return a * b;
	}
	inline ll lread()
	{
		R ll a = 0, b = 1; R char c = getchar();
		for(; c < '0' || c > '9'; c = getchar()) (c == '-') ? b = -1 : 0;
		for(; c >= '0' && c <= '9'; c = getchar()) a = (a << 1) + (a << 3) + c - '0';
		return a * b;
	}
	const int Maxn = 1010, Maxk = 21, Mod = 1000000007;
	int n, p, m, u, v, d, tmp, in[Maxk][Maxn], out[Maxn][Maxk];
	struct Matrix
	{
		int v[Maxk][Maxk];
		Matrix() { memset(v, 0, sizeof(v)); }
		Matrix operator + (const Matrix &b) const
		{
			R Matrix c;
			for(R int i = 1; i <= p; i++)
				for(R int j = 1; j <= p; j++)
					c.v[i][j] = (v[i][j] + b.v[i][j]) % Mod;
			return c;
		}
		Matrix operator * (const Matrix &b) const
		{
			R Matrix c;
			for(R int i = 1; i <= p; i++)
				for(R int k = 1; k <= p; k++) if(v[i][k])
					for(R int j = 1; j <= p; j++) if(b.v[k][j])
						c.v[i][j] = (c.v[i][j] + 1ll * v[i][k] * b.v[k][j] % Mod) % Mod;
			return c;
		}
	}E, A, Now, Ans;
	void Calc(R int x)
	{
		if(x == 1) { Now = Ans = A; }
		else 
		{
			Calc(x >> 1);
			Ans = Ans * (E + Now), Now = Now * Now;
			if(x & 1) Now = Now * A, Ans = Ans + Now;
		}
	}
	int Main()
	{
		n = read(), p = read();
		for(R int i = 1; i <= n; i++)
		{
			for(R int j = 1; j <= p; j++) out[i][j] = read() % Mod;
			for(R int j = 1; j <= p; j++) in[j][i] = read() % Mod;
		}
		for(R int i = 1; i <= p; i++) E.v[i][i] = 1;
		for(R int i = 1; i <= p; i++)
			for(R int k = 1; k <= n; k++) if(in[i][k])
				for(R int j = 1; j <= p; j++) if(out[k][j])
					A.v[i][j] = (A.v[i][j] + 1ll * in[i][k] * out[k][j] % Mod) % Mod;
		m = read();
		while(m--)
		{
			u = read(), v = read(), d = read();
			tmp = (u == v);
			if(d) for(R int i = 1; i <= p; i++) tmp = (tmp + 1ll * out[u][i] * in[i][v] % Mod) % Mod;
			if(d > 1)
			{
				Calc(d - 1);
				for(R int i = 1; i <= p; i++)
					for(R int j = 1; j <= p; j++)
						tmp = (tmp + 1ll * out[u][i] * in[j][v] % Mod * Ans.v[i][j] % Mod) % Mod;
			}
			printf("%d\n", tmp);
		}
		return 0;
	}
}
int main()
{
	return Dntcry :: Main();
}

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