BZOJ4386 [POI2015]Wycieczki 矩阵+倍增

题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=4386

题解

一眼就可以看出来是邻接矩阵快速幂。

可是这里的边权不为 \(1\)。不过可以发现,边权最多为 \(3\)。但是边的数量很多,不适合拆边,那就拆点吧。对于一条 \(x \to y\) 的边,就建立一个 \(x_0\to y_{w - 1}\) 的边,\(w\) 为边权。

然后就建立矩阵就可以了。因为我们需要统计第 \(i\) 步之前一共有多少路径,所以可以新建一个节点,每个点向这个点连一条有向边,这个点自己再来一个自环。

然后预处理 \(B_i\) 为走了 \(2^i\) 步的矩阵,直接倍增出来答案就可以了。


下面是代码,矩阵乘法的复杂度为 \(O(n^3)\),一共倍增 \(O(\log k)\) 次,因此总的时间复杂度为 \(O(n^3\log k)\)

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;

template<typename I>
inline void read(I &x) {
	int f = 0, c;
	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
	x = c & 15;
	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
	f ? x = -x : 0;
}

const int N = 40 * 3 + 7;

int n, m;
ll k;

struct Matrix {
	ll a[N][N];
	inline Matrix() { memset(a, 0, sizeof(a)); }
	
	inline Matrix operator * (const Matrix &b) {
		Matrix c;
		for (int k = 0; k <= n; ++k)
			for (int i = 0; i <= n; ++i)
				for (int j = 0; j <= n; ++j)
					c.a[i][j] += a[i][k] * b.a[k][j];
		return c;
	}
	
	inline void print() const {
		for (int i = 0; i <= n; ++i) {
			for (int j = 0; j <= n; ++j) dbg("%lld ", a[i][j]);
			dbg("\n");
		}
	}
} A, B[N];

inline bool isfull(const Matrix &a) {
	ll cnt = 0;
	for (int i = 1; i <= n / 3; ++i) {
		cnt += a.a[i][0] - 1;
		if (cnt >= k) return 1;
	}
	return 0;
}

inline void work() {
	n = n * 3, B[0] = A;
	int lim = 0;
	for (int i = 1; i <= 70; ++i) {
		B[i] = B[i - 1] * B[i - 1];
		++lim;
		if (isfull(B[i])) break;
	}
	if (!isfull(B[lim--])) {
		puts("-1");
		return;
	}
	memset(A.a, 0, sizeof(A.a));
	for (int i = 0; i <= n; ++i) A.a[i][i] = 1;
	ll ans = 0;
	for (int i = lim; ~i; --i) {
		const Matrix &tmp = A * B[i];
		if (!isfull(tmp)) A = tmp, ans += 1ll << i;
	}
	printf("%lld\n", ans);
}

inline void init() {
	read(n), read(m), read(k);
	for (int i = 1; i <= m; ++i) {
		int x, y, z;
		read(x), read(y), read(z);
		if (z == 1) ++A.a[x][y];
		if (z == 2) ++A.a[x][y + n];
		if (z == 3) ++A.a[x][y + n * 2];
	}
	for (int i = 1; i <= n; ++i) A.a[i][0] = A.a[i + n][i] = A.a[i + n * 2][i + n] = 1;
	A.a[0][0] = 1;
}

int main() {
#ifdef hzhkk 
	freopen("hkk.in", "r", stdin);
#endif
	init();
	work();
	fclose(stdin), fclose(stdout);
	return 0;
}
posted @ 2019-09-09 23:41  hankeke303  阅读(167)  评论(0编辑  收藏  举报