Files
cpp-courseware/2.Course/2.深入浅出程序设计竞赛(提高篇)/最短路/C++源码/07_02_p1875.cpp
T

45 lines
1.6 KiB
C++

// P1875 魔法药水。每个原料位置独立选择制法,交换配方书写顺序不重复计数。
// 当前原题提示同一对原料可能有不同产物,必须保存所有不同配方。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll addSat(ll a, ll b) { return a > LLONG_MAX - b ? LLONG_MAX : a + b; }
ll mulSat(ll a, ll b) {
if (a == 0 || b == 0) return 0;
return a > LLONG_MAX / b ? LLONG_MAX : a * b;
}
struct Recipe { int a, b, c; };
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
int n; if (!(cin >> n)) return 0;
vector<ll> d(n), ways(n, 1);
for (ll &x : d) cin >> x;
vector<Recipe> rec;
vector<vector<int>> incident(n);
unordered_set<ll> seen;
int a, b, c;
while (cin >> a >> b >> c) {
if (a > b) swap(a, b);
ll key = (1LL * a * n + b) * n + c;
if (!seen.insert(key).second) continue;
int id = (int)rec.size(); rec.push_back({a, b, c});
incident[a].push_back(id); incident[b].push_back(id);
}
vector<int> need(rec.size(), 2);
vector<bool> done(n, false);
for (int round = 0; round < n; ++round) {
int u = -1;
for (int i = 0; i < n; ++i)
if (!done[i] && (u == -1 || d[i] < d[u])) u = i;
done[u] = true;
for (int id : incident[u]) {
if (--need[id] != 0) continue;
auto [a, b, c] = rec[id];
ll nd = d[a] + d[b], cnt = mulSat(ways[a], ways[b]);
if (nd < d[c]) { d[c] = nd; ways[c] = cnt; }
else if (nd == d[c]) ways[c] = addSat(ways[c], cnt);
}
}
cout << d[0] << ' ' << ways[0] << '\n';
}