[CF576D]Flights for Regular Customers

题目大意:有一张$n$个点$m$条边的有向图,第$i$条边有个权值$d_i$表示至少要走$d_i$条边才可以经过这条边(可重复),问从点$1$到点$n$最少经过几条边(重复算多次),无解输出$-1$。$n,m\leqslant150,d_i\leqslant 10^9$

题解:按$d_i$排序,一条条加入转移矩阵,可以用邻接矩阵算出走恰好$k$次可以到达的位置。可以发现,在一个行的转移矩阵下,若点$1$可以走到点$n$,最多走$n-1$步。于是可以先暴力走$n-1$次,若还不能到达$n$,就用矩阵快速幂计算。复杂度$O(n^4m(\log_2 d+n))$。可以令一个向量表示点$1$可以到达的点,就变成向量乘矩阵,复杂度少一个$n$,已经可以通过了。也可以用$\mathrm{bitset}$优化乘法,复杂度$O(\dfrac{n^3m(\log_2d+n)}{\omega})$

卡点:

 

C++ Code:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <bitset>
const int maxn = 160;
typedef std::bitset<maxn> B8;

int n, m;
struct Matrix {
	B8 s[maxn];
	Matrix() { for (int i = 0; i < n; ++i) s[i].reset(); }
	Matrix operator * (const Matrix &rhs) {
		Matrix res;
		for (int i = 0; i < n; ++i)
			for (int j = 0; j < n; ++j)
				if (s[i][j]) res.s[i] |= rhs.s[j];
		return res;
	}
} base;
B8 operator * (const B8 &lhs, const Matrix &rhs) {
	B8 res; res.reset();
	for (int i = 0; i < n; ++i)
		if (lhs[i]) res |= rhs.s[i];
	return res;
}
B8 R;

struct Edge {
	int a, b, d;
	inline bool operator < (const Edge &rhs) const { return d < rhs.d; }
} e[maxn];

int check(int N) {
	for (int i = 1; i <= N; ++i) {
		R = R * base;
		if (R[n - 1]) return i;
	}
	return N + 1;
}
void pw(int p) {
	Matrix b = base;
	for (; p; p >>= 1, b = b * b) if (p & 1) R = R * b;
}
int solve() {
	int p = 1, res = 0;
	for (; p <= m && e[p].d == 0; ++p) base.s[e[p].a - 1].set(e[p].b - 1);
	if (p == 1) return 0;
	R.set(0);
	for (int t, o; p <= m; ++p) {
		t = e[p].d - e[p - 1].d;
		if (t <= n) {
			o = check(t);
			if (o > t) res += t;
			else return res + o;
		} else {
			o = check(n);
			if (o > n) pw(t - n), res += t;
			else return res + o;
		}
		base.s[e[p].a - 1].set(e[p].b - 1);
	}
	int o = check(n);
	if (o > n) return 0;
	return res + o;
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	std::cin >> n >> m;
	for (int i = 1; i <= m; ++i)
		std::cin >> e[i].a >> e[i].b >> e[i].d;
	std::sort(e + 1, e + m + 1);
	int ans = solve();
	if (!ans) std::cout << "Impossible\n";
	else std::cout << ans << '\n';
	return 0;
}

  

posted @ 2019-11-03 18:39  Memory_of_winter  阅读(237)  评论(0编辑  收藏  举报