#include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef long long ll; typedef unsigned long long ull; typedef long double ldb; /// /// どれがいくつ入ってるかを高速(?)にソートする。 /// /// template class MultiNum { map elementToIdMap; map idToElementMap; vector> elementNum; vector> sorted; public: void Add(T element) { if (elementToIdMap.count(element) <= 0) { elementNum.push_back(pair(0, elementToIdMap.size())); idToElementMap[elementToIdMap.size()] = element; elementToIdMap[element] = elementToIdMap.size(); } elementNum[elementToIdMap[element]].first++; } void SortLess() { sorted = elementNum; sort(sorted.begin(), sorted.end()); } void SortGreater() { sorted = elementNum; sort(sorted.begin(), sorted.end(), greater>()); } vector> GetResult() { vector> result; for (ll i = 0; i < sorted.size(); i++) { result.push_back(pair(idToElementMap[sorted[i].second], sorted[i].first)); } return result; } }; class nCk { const ll divs; const ll maxSize; vector fac; vector invFac; ll divsPow(ll base, ll exponent) { ll answer = 1; while (0 < exponent) { if (exponent & 1) { answer = (answer * base) % divs; exponent--; continue; } base = (base * base) % divs; exponent = exponent >> 1; } return answer; } public: nCk(ll _divs, ll _max) : divs(_divs), maxSize(_max) { //index0,1は全て1と考えられる。 fac.push_back(1); fac.push_back(1); invFac.push_back(1); invFac.push_back(1); for (ll i = 2; i <= maxSize; i++) { fac.push_back((fac[i - 1] * i) % divs); invFac.push_back((invFac[i - 1] * divsPow(i, divs - 2)) % divs); } } ll Execute(ll n, ll k) { if (n < k) return 0; if (n < 0 || k < 0) return 0; return (fac[n] * ((invFac[k] * invFac[n - k]) % divs)) % divs; } }; template class IdMap { set _isExist; map _map; function _newIdAction; public: IdMap(function newIdAction) { _newIdAction = newIdAction; } ll getId(Ty id) { if (_isExist.count(id) <= 0) { _isExist.insert(id); _map[id] = _map.size(); _newIdAction(id); } return _map[id]; } }; class UnionFind { private: vector parent; public: UnionFind(int size) : parent(size, -1) { // iota(parent.begin(), parent.end(), -1); } int FindRoot(int v) { // -1ならrootは自分になる。 if (parent[v] < 0) return v; // root更新していく parent[v] = FindRoot(parent[v]); return parent[v]; } void Unite(int a, int b) { int rootA = FindRoot(a); int rootB = FindRoot(b); // rootが同じなら何もしない。 if (rootA == rootB) return; parent[rootB] = rootA; } bool IsSameRoot(int a, int b) { if (FindRoot(a) == FindRoot(b)) return true; else return false; } }; template class SegmentTree { vector e; size_t size; function calc; const T identity; size_t get_new_size(size_t prevSize) { size_t newSize = 1; for (; newSize < prevSize; newSize *= 2) {} return newSize; } size_t get_eId(size_t id) { return id + size; } void updateFromChildren(size_t eId) { if (eId == 0) return; e[eId] = calc(e[eId * 2], e[eId * 2 + 1]); updateFromChildren(eId / 2); } T getRange(size_t eId, size_t lIdFromEId, size_t rIdFromEId, size_t lIdNeed, size_t rIdNeed) { // 完全に範囲外にでた if (rIdNeed <= lIdFromEId || rIdFromEId <= lIdNeed) { return identity; } // 完全に囲まれた if (lIdNeed <= lIdFromEId && rIdFromEId <= rIdNeed) { return e[eId]; } // まだ絞り切れてない return calc( getRange(eId * 2, lIdFromEId, (rIdFromEId + lIdFromEId) / 2, lIdNeed, rIdNeed), getRange(eId * 2 + 1, (rIdFromEId + lIdFromEId) / 2, rIdFromEId, lIdNeed, rIdNeed) ); } public: SegmentTree(size_t _size, T initNum, function _calc) : size(get_new_size(_size)), identity(initNum), calc(_calc) { e.resize(2 * size, identity); } void update(size_t id, T newValue) { auto elementId = get_eId(id); e[elementId] = newValue; updateFromChildren(elementId / 2); } T getOne(size_t id) { return e[get_eId(id)]; } /// /// [leftId, rightId) /// T getRange(size_t leftId, size_t rightId) { size_t start_eId = 1; size_t lIdFromEId = 0, rIdFromEId = size; return getRange(start_eId, lIdFromEId, rIdFromEId, leftId, rightId); } }; template class LazySegmentTree { vector e; vector lazyE; vector hasLazyValue; size_t size; function calc; function operateByLazy; const T identity; size_t get_new_size(size_t prevSize) { size_t newSize = 1; for (; newSize < prevSize; newSize *= 2) {} return newSize; } size_t get_eId(size_t id) { return id + size; } void updateRange(size_t eId, size_t lIdFromEId, size_t rIdFromEId, size_t lIdNeed, size_t rIdNeed, T newValue) { // 完全に範囲外にでた if (rIdNeed <= lIdFromEId || rIdFromEId <= lIdNeed) { return; } // 完全に囲まれた if (lIdNeed <= lIdFromEId && rIdFromEId <= rIdNeed) { e[eId] = operateByLazy(e[eId], newValue); if (eId < size) { lazyE[eId * 2] = newValue; lazyE[eId * 2 + 1] = newValue; hasLazyValue[eId * 2] = true; hasLazyValue[eId * 2 + 1] = true; } return; } // まだ絞り切れてない updateRange(eId * 2, lIdFromEId, (rIdFromEId + lIdFromEId) / 2, lIdNeed, rIdNeed, newValue); updateRange(eId * 2 + 1, (rIdFromEId + lIdFromEId) / 2, rIdFromEId, lIdNeed, rIdNeed, newValue); // 子のupdateに応じて親をupdateさせる e[eId] = calc(e[eId * 2], e[eId * 2 + 1]); } T getRange(size_t eId, size_t lIdFromEId, size_t rIdFromEId, size_t lIdNeed, size_t rIdNeed) { //lazy評価 if (hasLazyValue[eId]) { e[eId] = operateByLazy(e[eId], lazyE[eId]); hasLazyValue[eId] = false; // 子がいるなら子にも伝搬する if (eId < size) { lazyE[eId * 2] = lazyE[eId]; lazyE[eId * 2 + 1] = lazyE[eId]; hasLazyValue[eId * 2] = true; hasLazyValue[eId * 2 + 1] = true; } } // 完全に範囲外にでた if (rIdNeed <= lIdFromEId || rIdFromEId <= lIdNeed) { return identity; } // 完全に囲まれた if (lIdNeed <= lIdFromEId && rIdFromEId <= rIdNeed) { return e[eId]; } // まだ絞り切れてない e[eId] = calc( getRange(eId * 2, lIdFromEId, (rIdFromEId + lIdFromEId) / 2, lIdNeed, rIdNeed), getRange(eId * 2 + 1, (rIdFromEId + lIdFromEId) / 2, rIdFromEId, lIdNeed, rIdNeed) ); return e[eId]; } public: LazySegmentTree(size_t _size, T initNum, function _calc, function _operateByLazy) : size(get_new_size(_size)), identity(initNum), calc(_calc), operateByLazy(_operateByLazy) { e.resize(2 * size, identity); lazyE.resize(2 * size, identity); hasLazyValue.resize(2 * size, false); } void updateRange(size_t leftId, size_t rightId, T newValue) { size_t start_eId = 1; size_t lIdFromEId = 0, rIdFromEId = size; return updateRange(start_eId, lIdFromEId, rIdFromEId, leftId, rightId, newValue); } void update(size_t id, T newValue) { updateRange(id, id + 1, newValue); } /// /// [leftId, rightId) /// T getRange(size_t leftId, size_t rightId) { size_t start_eId = 1; size_t lIdFromEId = 0, rIdFromEId = size; return getRange(start_eId, lIdFromEId, rIdFromEId, leftId, rightId); } T getOne(size_t id) { return getRange(id, id + 1); } }; class scc { ll n; vector> groups; void searchMe(ll id, ll& nowScore, vector& score, vector>& edge) { if (0 <= score[id]) return; score[id] = 0; for (auto& p : edge[id]) { searchMe(p, nowScore, score, edge); } score[id] = nowScore++; } void reverseSearchMe(ll id, vector& cameIds, vector& hasCame, vector>& edge) { if (hasCame[id]) return; hasCame[id] = true; cameIds.push_back(id); for (auto& p : edge[id]) { reverseSearchMe(p, cameIds, hasCame, edge); } } public: scc(ll _n, vector> _edge) : n(_n) { vector> edge(n), backE(n); for (auto& e : _edge) { edge[e.first].push_back(e.second); backE[e.second].push_back(e.first); } vector score(n, -1); ll nowScore = 0; for (ll i = 0; i < n; i++) { searchMe(i, nowScore, score, edge); } vector idScore(n, -1); for (ll i = 0; i < n; i++) { idScore[score[i]] = i; } vector hasCame(n, false); for (ll i = n - 1; 0 <= i; i--) { vector cameIds; reverseSearchMe(idScore[i], cameIds, hasCame, backE); groups.push_back(cameIds); } } vector>& getGroups() { return groups; } }; template class queueVec { ll sItr, eItr; vector vec; public: queueVec(ll capacity) { sItr = 0; eItr = 0; vec.reserve(capacity); } ll size() { return eItr - sItr; } void push(T value) { eItr++; vec.emplace_back(value); } void pop() { sItr++; } T front() { return vec[sItr]; } }; class Lca { vector> parents; vector> es; vector depths; ll maxDepthLog2; public: Lca(ll n, vector>& edges) { ll kaisou = log2l(n - 1) + 1; parents = vector>(n, vector(kaisou, -1)); depths = vector(n); // make tree { es = vector>(n); for (auto& e : edges) { es[e.first].push_back(e.second); es[e.second].push_back(e.first); } parents[0][0] = 0; queueVec queueP(n); queueP.push(0); ll d = 0; for (d = 0; 0 < queueP.size(); d++) { ll qNum = queueP.size(); for (ll q = 0; q < qNum; q++) { auto p = queueP.front(); queueP.pop(); depths[p] = d; for (auto& np : es[p]) { if (parents[np][0] < 0) { parents[np][0] = p; queueP.push(np); } } } } maxDepthLog2 = (ll)log2l(d - 1) + 1; for (ll k = 1; k < kaisou; k++) { for (ll i = 0; i < n; i++) { parents[i][k] = parents[parents[i][k - 1]][k - 1]; } } } } ll getAncestor(ll v, ll steps) { for (ll k = 0, k2 = 1; k2 <= steps; k++, k2 *= 2) { if (0 < (k2 & steps)) { v = parents[v][k]; } } return v; } ll commonAncestor(ll a, ll b) { if (depths[a] < depths[b]) { b = getAncestor(b, depths[b] - depths[a]); } else if (depths[b] < depths[a]) { a = getAncestor(a, depths[a] - depths[b]); } if (a == b) return a; for (ll k = maxDepthLog2; 0 <= k; k--) { if (parents[a][k] == parents[b][k]) continue; a = parents[a][k]; b = parents[b][k]; } return parents[a][0]; } ll distance(ll a, ll b) { return depths[a] + depths[b] - 2 * depths[commonAncestor(a, b)]; } pair diameterVs() { ll v; ll maxD = -1; for (ll i = 0; i < depths.size(); i++) { if (maxD < depths[i]) { maxD = depths[i]; v = i; } } pair answer = { v, v }; ll farV = -1; queueVec nextP(depths.size()); vector isReached(depths.size(), false); nextP.push(v); isReached[v] = true; while (0 < nextP.size()) { ll qSize = nextP.size(); for (ll q = 0; q < qSize; q++) { auto p = nextP.front(); nextP.pop(); farV = p; for (auto& np : es[p]) { if (isReached[np]) continue; isReached[np] = true; nextP.push(np); } } } answer.second = farV; return answer; } }; int main() { ll n, m, k; cin >> n >> m >> k; vector c(m); for (ll i = 0; i < m; i++) cin >> c[i]; vector> uv(n); for (ll i = 0; i < m; i++) { ll u, v; cin >> u >> v; u--; v--; uv[u][v] = i; uv[v][u] = i; } vector> dp(n, vector(k + 1, LLONG_MAX)); { stack> pStack; pStack.push({ 0, 0 }); while (0 < pStack.size()) { auto nowp = pStack.top(); pStack.pop(); if (dp[nowp.first][0] <= nowp.second) continue; dp[nowp.first][0] = nowp.second; for (auto& p : uv[nowp.first]) { pStack.push({ p.first, nowp.second + c[uv[nowp.first][p.first]] }); } } } for (ll kk = 0; kk < k; kk++) { priority_queue, vector>, greater>> pStack; dp[0][kk + 1] = 1000000000000000; pStack.push({ 0, 0 }); while (0 < pStack.size()) { auto nowp = pStack.top(); pStack.pop(); if (dp[nowp.second][kk + 1] < nowp.first) { continue; } for (auto& p : uv[nowp.second]) { ll nextScore = min(dp[nowp.second][kk], dp[nowp.second][kk + 1] + c[uv[nowp.second][p.first]]); if (dp[p.first][kk + 1] <= nextScore) continue; dp[p.first][kk + 1] = nextScore; pStack.push({ nextScore, p.first }); } } } ll answer = LLONG_MAX; for (auto& co : dp[n - 1]) answer = min(answer, co); if (answer == LLONG_MAX) answer = -1; cout << answer << endl; }