結果

問題 No.3653 Space-Time Courier
コンテスト
ユーザー kwm_t
提出日時 2026-08-29 03:05:56
言語 C++23
(gcc 15.2.0 + boost 1.90.0)
コンパイル:
g++-15 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
AC  
実行時間 627 ms / 4,000 ms
+ 831µs
コード長 6,402 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 2,999 ms
コンパイル使用メモリ 355,552 KB
実行使用メモリ 53,120 KB
最終ジャッジ日時 2026-08-29 03:06:06
合計ジャッジ時間 9,775 ms
ジャッジサーバーID
(参考情報)
judge2_0 / judge1_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other AC * 28
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <bits/stdc++.h>
//#include <atcoder/all>
using namespace std;
// using namespace atcoder;
// using mint = modint1000000007;
// const int mod = 1000000007;
// using mint = modint998244353;
// const int mod = 998244353;
// const int INF = 1e9;
const long long LINF = 1e18;
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define rep2(i, l, r) for (int i = (l); i < (r); ++i)
#define rrep(i, n) for (int i = (n)-1; i >= 0; --i)
#define rrep2(i, l, r) for (int i = (r)-1; i >= (l); --i)
#define all(x) (x).begin(), (x).end()
#define allR(x) (x).rbegin(), (x).rend()
#define P pair<int, int>
template<typename A, typename B> inline bool chmax(A& a, const B& b) { if (a < b) { a = b; return true; } return false; }
template<typename A, typename B> inline bool chmin(A& a, const B& b) { if (a > b) { a = b; return true; } return false; }
#ifndef KWM_T_GRAPH_SHORTEST_PATH_DIJKSTRA_HPP
#define KWM_T_GRAPH_SHORTEST_PATH_DIJKSTRA_HPP

#include <vector>
#include <queue>
#include <limits>
#include <utility>
#include <functional>
#include <algorithm>

/**
 * @brief ダイクストラ法(単一始点最短路 + 経路復元用情報)
 *
 * 非負重みグラフにおける単一始点最短路を求める。
 * prev を用いることで最短経路の復元が可能。
 *
 * 典型用途:
 *   - 重み付きグラフ(非負)
 *   - グリッド + コスト
 *   - 最短経路 + 経路復元
 *
 * 計算量:
 *   O((V + E) log V)
 *
 * @tparam T 距離型(int, long long など)
 *
 * @param g 隣接リスト (to, cost)
 * @param s 始点
 * @param inf 無限大
 *
 * @return pair(dist, prev)
 *
 * 制約 / 注意:
 *   - 負辺がある場合は使用不可(Bellman-Fordを使う)
 *
 * 使用例:
 *   auto [dist, prev] = dijkstra(g, s, INF);
 *   auto path = restore_path(prev, s, t);
 *
 * verified:
 *   https://atcoder.jp/contests/awc0033/submissions/74392079
 */
namespace kwm_t::graph::shortest_path {

template<typename T>
std::pair<std::vector<T>, std::vector<int>>
dijkstra(const std::vector<std::vector<std::pair<int, T>>>& g, int s, T inf) {
	int n = (int)g.size();

	std::vector<T> dist(n, inf);
	std::vector<int> prev(n, -1);

	using S = std::pair<T, int>;
	std::priority_queue<S, std::vector<S>, std::greater<S>> pq;

	dist[s] = 0;
	pq.emplace(0, s);

	while (!pq.empty()) {
		auto [d, v] = pq.top();
		pq.pop();

		if (d > dist[v]) continue;

		for (auto [to, cost] : g[v]) {
			if (dist[v] > inf - cost) continue; // overflow guard

			T nd = dist[v] + cost;
			if (nd < dist[to]) {
				dist[to] = nd;
				prev[to] = v;
				pq.emplace(nd, to);
			}
		}
	}

	return { dist, prev };
}

/**
 * @brief 経路復元
 * @param prev dijkstra で得た prev
 * @param s 始点
 * @param t 終点
 * @return s -> t の最短経路(存在しない場合は空)
 */
inline std::vector<int>
restore_path(const std::vector<int>& prev, int s, int t) {
	std::vector<int> path;
	for (int v = t; v != -1; v = prev[v]) {
		path.push_back(v);
	}
	std::reverse(path.begin(), path.end());

	if (path.empty() || path[0] != s) return {};
	return path;
}

} // namespace kwm_t::graph::shortest_path

#endif // KWM_T_GRAPH_SHORTEST_PATH_DIJKSTRA_HPP

#ifndef KWM_T_GRAPH_SHORTEST_PATH_JOHNSON_HPP
#define KWM_T_GRAPH_SHORTEST_PATH_JOHNSON_HPP

#include <vector>
#include <utility>

// #include "dijkstra.hpp"

/**
 * @brief Johnson's Algorithm(負辺対応・全点対最短路)
 *
 * 負辺を含む有向グラフに対して、全頂点対の最短距離を求める。
 * 負閉路が存在しないことを仮定する。
 *
 * 全頂点を初期距離 0 とした Bellman-Ford 法でポテンシャルを計算し、
 * 各辺を非負重みに変換した後、各頂点から Dijkstra 法を実行する。
 *
 * 典型用途:
 *   - 負辺を含むグラフの全点対最短路
 *   - 疎グラフの全点対最短路
 *
 * 計算量:
 *   O(VE + V(V + E) log V)
 *
 * @tparam T 距離・辺重みの型
 *
 * @param g 隣接リスト (to, cost)
 * @param inf 無限大
 *
 * @return dist[i][j]
 *   頂点 i から頂点 j への最短距離。
 *   到達不能な場合は inf。
 *
 * 制約 / 注意:
 *   - 負閉路が存在しないこと
 *   - inf は十分大きな値を指定すること
 *
 * 使用例:
 *   using T = long long;
 *
 *   std::vector<std::vector<std::pair<int, T>>> g(n);
 *   g[0].emplace_back(1, -5);
 *   g[1].emplace_back(2, 10);
 *
 *   auto dist = johnson(g, INF);
 *
 * verified:
 *   未verified
 */
namespace kwm_t::graph::shortest_path {

template<typename T>
std::vector<std::vector<T>> johnson(const std::vector<std::vector<std::pair<int, T>>>& g, T inf) {

	const int n = (int)g.size();

	// 1. ポテンシャルの計算
	// 超頂点から全頂点へ重み 0 の辺を張る代わりに、
	// 全頂点の初期距離を 0 として Bellman-Ford を行う。
	std::vector<T> h(n, 0);
	for (int i = 0; i < n - 1; ++i) {
		bool updated = false;
		for (int u = 0; u < n; ++u) {
			for (auto [v, cost] : g[u]) {
				if (h[u] + cost < h[v]) {
					h[v] = h[u] + cost;
					updated = true;
				}
			}
		}
		if (!updated) break;
	}

	// 2. 辺の重みを非負化
	// new_cost = cost + h[u] - h[v]
	std::vector<std::vector<std::pair<int, T>>> reweighted_g(n);

	for (int u = 0; u < n; ++u) {
		reweighted_g[u].reserve(g[u].size());

		for (auto [v, cost] : g[u]) {
			T new_cost = cost + h[u] - h[v];
			reweighted_g[u].emplace_back(v, new_cost);
		}
	}

	// 3. 各頂点から Dijkstra
	std::vector<std::vector<T>> dist(n, std::vector<T>(n, inf));

	for (int s = 0; s < n; ++s) {
		auto [d, prev] = dijkstra(reweighted_g, s, inf);

		for (int t = 0; t < n; ++t) {
			if (d[t] >= inf) continue;

			// 元の距離へ復元
			dist[s][t] = d[t] - h[s] + h[t];
		}
	}
	return dist;
}

} // namespace kwm_t::graph::shortest_path

#endif // KWM_T_GRAPH_SHORTEST_PATH_JOHNSON_HPP
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	int n, m; cin >> n >> m;
	vector<int>p(n);
	rep(i, n)cin >> p[i];
	vector g(n, vector<pair<int, long long>>());
	rep(i, m) {
		int u, v, t; cin >> u >> v >> t;
		u--, v--;
		g[u].emplace_back(v, t);
	}
	auto dist = kwm_t::graph::shortest_path::johnson(g, LINF);
	long long ans = LINF;
	int cnt = 0;
	rep(i, n)rep(j, n)if (i != j) {
		auto d = dist[i][j] + p[i] + p[j];
		if (chmin(ans, d))cnt = 0;
		if (ans == d)cnt++;
	}
	cout << ans << "  " << cnt << endl;
	return 0;
}
0