結果
問題 | No.1283 Extra Fee |
ユーザー | kjnh10 |
提出日時 | 2020-11-06 22:55:36 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 556 ms / 2,000 ms |
コード長 | 22,138 bytes |
コンパイル時間 | 2,626 ms |
コンパイル使用メモリ | 233,516 KB |
実行使用メモリ | 219,320 KB |
最終ジャッジ日時 | 2024-11-16 06:51:06 |
合計ジャッジ時間 | 11,098 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
6,816 KB |
testcase_01 | AC | 2 ms
6,816 KB |
testcase_02 | AC | 2 ms
6,816 KB |
testcase_03 | AC | 2 ms
6,820 KB |
testcase_04 | AC | 2 ms
6,820 KB |
testcase_05 | AC | 2 ms
6,816 KB |
testcase_06 | AC | 2 ms
6,816 KB |
testcase_07 | AC | 2 ms
6,816 KB |
testcase_08 | AC | 2 ms
6,820 KB |
testcase_09 | AC | 2 ms
6,820 KB |
testcase_10 | AC | 2 ms
6,816 KB |
testcase_11 | AC | 26 ms
16,692 KB |
testcase_12 | AC | 31 ms
17,876 KB |
testcase_13 | AC | 18 ms
11,820 KB |
testcase_14 | AC | 87 ms
52,524 KB |
testcase_15 | AC | 131 ms
63,044 KB |
testcase_16 | AC | 33 ms
16,460 KB |
testcase_17 | AC | 502 ms
211,168 KB |
testcase_18 | AC | 499 ms
212,180 KB |
testcase_19 | AC | 490 ms
214,772 KB |
testcase_20 | AC | 501 ms
211,300 KB |
testcase_21 | AC | 520 ms
212,116 KB |
testcase_22 | AC | 451 ms
206,208 KB |
testcase_23 | AC | 509 ms
216,708 KB |
testcase_24 | AC | 483 ms
216,840 KB |
testcase_25 | AC | 531 ms
216,840 KB |
testcase_26 | AC | 556 ms
216,712 KB |
testcase_27 | AC | 521 ms
216,836 KB |
testcase_28 | AC | 554 ms
216,840 KB |
testcase_29 | AC | 543 ms
219,320 KB |
ソースコード
#line 2 "header.hpp" //%snippet.set('header')% //%snippet.fold()% #ifndef HEADER_H #define HEADER_H // template version 2.0 using namespace std; #include <bits/stdc++.h> // varibable settings template <class T> constexpr T inf = numeric_limits<T>::max() / 2.1; #define _overload3(_1, _2, _3, name, ...) name #define _rep(i, n) repi(i, 0, n) #define repi(i, a, b) for (ll i = (ll)(a); i < (ll)(b); ++i) #define rep(...) _overload3(__VA_ARGS__, repi, _rep, )(__VA_ARGS__) #define _rrep(i, n) rrepi(i, 0, n) #define rrepi(i, a, b) for (ll i = (ll)((b)-1); i >= (ll)(a); --i) #define r_rep(...) _overload3(__VA_ARGS__, rrepi, _rrep, )(__VA_ARGS__) #define each(i, a) for (auto &&i : a) #define all(x) (x).begin(), (x).end() #define sz(x) ((int)(x).size()) #define pb(a) push_back(a) #define mp(a, b) make_pair(a, b) #define mt(...) make_tuple(__VA_ARGS__) #define ub upper_bound #define lb lower_bound #define lpos(A, x) (lower_bound(all(A), x) - A.begin()) #define upos(A, x) (upper_bound(all(A), x) - A.begin()) template <class T, class U> inline void chmax(T &a, const U &b) { if ((a) < (b)) (a) = (b); } template <class T, class U> inline void chmin(T &a, const U &b) { if ((a) > (b)) (a) = (b); } template <typename X, typename T> auto make_table(X x, T a) { return vector<T>(x, a); } template <typename X, typename Y, typename Z, typename... Zs> auto make_table(X x, Y y, Z z, Zs... zs) { auto cont = make_table(y, z, zs...); return vector<decltype(cont)>(x, cont); } template <class T> T cdiv(T a, T b){ assert(a >= 0 && b > 0); return (a+b-1)/b; } #define is_in(x, a, b) ((a) <= (x) && (x) < (b)) #define uni(x) sort(all(x)); x.erase(unique(all(x)), x.end()) #define slice(l, r) substr(l, r - l) typedef long long ll; typedef long double ld; using vl = vector<ll>; using vvl = vector<vl>; using pll = pair<ll, ll>; template <typename T> using PQ = priority_queue<T, vector<T>, greater<T>>; void check_input() { assert(cin.eof() == 0); int tmp; cin >> tmp; assert(cin.eof() == 1); } #if defined(PCM) || defined(LOCAL) #else #define dump(...) ; #define dump_1d(...) ; #define dump_2d(...) ; #define cerrendl ; #endif #endif /* HEADER_H */ //%snippet.end()% #line 2 "solve.cpp" template<class T=ll> using vec = vector<T>; struct Fast { Fast() { std::cin.tie(0); ios::sync_with_stdio(false); } } fast; // snippet:segment_tree {{{ template <typename X> struct SegmentTree { // {{{ private: using F = function<X(X, X)>; using index = int; int n; // 元の配列のサイズ int N; // n以上の最小の2冪 vector<X> node; F merge; X identity; public: SegmentTree() {} SegmentTree(vector<X> a, F f, X id) : merge(f), identity(id) { n = (int)a.size(); N = 1; while (N < n) N *= 2; node.resize(2 * N - 1, identity); for (int i = 0; i < n; i++) node[i + N - 1] = a[i]; for (int i = N - 2; i >= 0; i--) node[i] = merge(node[2 * i + 1], node[2 * i + 2]); } SegmentTree(int sz, F f, X id) : SegmentTree(vector<X>(sz, id), f, id) {} X& operator[](index i) { return node[i + N - 1]; } void set(index i, X val) { i += (N - 1); node[i] = val; while (i > 0) { i = (i - 1) / 2; node[i] = merge(node[2 * i + 1], node[2 * i + 2]); } } void add(index i, X val) { i += (N - 1); node[i] += val; while (i > 0) { i = (i - 1) / 2; node[i] = merge(node[2 * i + 1], node[2 * i + 2]); } } // query for [a, b) X query(index a, index b, int k = 0, index l = 0, index r = -1) { if (r < 0) r = N; if (r <= a || b <= l) return identity; if (a <= l && r <= b) return node[k]; X lv = query(a, b, 2 * k + 1, l, (l + r) / 2); X rv = query(a, b, 2 * k + 2, (l + r) / 2, r); return merge(lv, rv); } index find_most_left(index l, const function<bool(X)>& is_ok){ // lから右に探していってis_okが初めて成り立つようなindexを返す。 // assume query(l, *) has monotonity // return index i s.t is_ok(query(l, i)) does not holds, but is_ok(query(l, i+1)) does. // if such i does not exist, return n index res = _find_most_left(l, is_ok, 0, 0, N, identity).first; assert(l <= res); return res; } pair<index, X> _find_most_left(index a, const function<bool(X)>& is_ok, int k, index l, index r, X left_value){ // params: // left_value = (a < l ? query(a, l) : ex) // return (index i, X v) // i is the index in [a, n)^[l, r) s.t query(a, i+1) is ok but query(a, i) isn't ok. if such i does not exist, i = n // v is the value s.t query(a, r) if (r <= a) return {n, identity}; // 区間が全く被っていない else if (a <= l && !is_ok(merge(left_value, node[k]))) return {n, merge(left_value, node[k])}; else if (k >= N-1) return {k - (N-1), merge(left_value, node[k])}; else{ auto [lv, xl] = _find_most_left(a, is_ok, 2 * k + 1, l, (l + r) / 2, left_value); if (lv != n) return {lv, xl}; auto [rv, xr] = _find_most_left(a, is_ok, 2 * k + 2, (l + r) / 2, r, xl); return {rv, xr}; } } index find_most_right(index r, const function<bool(X)>& is_ok){ // rから左に探していってis_okが初めて成り立つようなindexを返す。 // assume query(*, r) has monotonity // return index i s.t is_ok(query(i+1, r+1)) does not holds, but is_ok(query(i, r+1)) does. // if such i does not exist, return -1 index res = _find_most_right(r+1, is_ok, 0, 0, N, identity).first; assert(res <= r); return res; } pair<index, X> _find_most_right(index b, const function<bool(X)>& is_ok, int k, index l, index r, X right_value){ if (b <= l) return {-1, identity}; // 区間が全く被っていない else if (r <= b && !is_ok(merge(node[k], right_value))) return {-1, merge(node[k], right_value)}; else if (k >= N-1) return {k - (N-1), merge(node[k], right_value)}; else{ auto [rv, xr] = _find_most_right(b, is_ok, 2 * k + 2, (l + r) / 2, r, right_value); if (rv != -1) return {rv, xr}; auto [lv, xl] = _find_most_right(b, is_ok, 2 * k + 1, l, (l + r) / 2, xr); return {lv, xl}; } } #if defined(PCM) || defined(LOCAL) friend ostream& operator<<(ostream& os, SegmentTree<X>& sg) { // os << "["; for (int i = 0; i < sg.n; i++) { os << sg[i] << (i == sg.n - 1 ? "]\n" : ", "); } return os; } #endif };/*}}}*/ // sample of initialize SegmentTree: // ----------------------------------------------- // auto mymin=[](auto a, auto b){return min(a,b);}; // ll e = 1e18; // SegmentTree<ll> seg(a, mymin, e); // auto mymax=[](auto a, auto b){return max(a,b);}; // ll e = -1e18; // SegmentTree<ll> seg(a, mymax, e); // auto add=[](auto a, auto b){return a+b;}; // ll e = 0; // SegmentTree<ll> seg(a, add, e); // pair<int, int> get_nearest_index_of_smaller_element(int i){ // auto left = seg.find_most_right(i, [&](auto x){return x < a[i];}); // auto right = seg.find_most_left(i, [&](auto x){return x < a[i];}); // return {left, right}; // } // ----------------------------------------------- // snippet:segment_tree }}} // snippet:edge {{{ template<class Cost=ll> struct Edge { int from, to; Cost cost; int idx; Edge(){}; Edge(int from_, int to_, Cost cost_, int idx_) : from(from_), to(to_), cost(cost_), idx(idx_) {} friend ostream& operator<<(ostream& os, const Edge& e) { // os << "(f:" << e.from << ", t:" << e.to << ", c:" << e.cost << ", i" << e.idx << ")"; // detailed os << "(" << e.from << "," << e.to << ")"; return os; } }; // snippet:edge }}} // snippet:union_find {{{ struct union_find { vector<int> par; // par[x]: parent of x. if root, -size. int gcount; // count of groups union_find() {} union_find(int _n) : par(_n, -1), gcount(_n) {} bool merge(int x, int y) { x = root(x); y = root(y); if (x != y) { if (par[y] < par[x]) swap(x, y); par[x] += par[y]; par[y] = x; gcount--; } return x != y; } int root(int x) { if (is_root(x)){ return x; } else{ return par[x] = root(par[x]); // 経路圧縮 // return root(par[x]); // 経路圧縮なし } } bool is_root(int x) { return par[x] < 0; } bool same(int x, int y) { return root(x) == root(y); } int size(int x) { return -par[root(x)]; } map<int, vector<int>> group(){ map<int, vector<int>> res; rep(i, sz(this->par)) { res[this->root(i)].pb(i); } return res; } #if defined(PCM) || defined(LOCAL) // {{{ friend ostream& operator<<(ostream& os, union_find& uf) { auto group = uf.group(); os << endl; each(g, group) { os << g << endl; } return os; } #endif // }}} }; // snippet:union_find }}} // snippet:tree {{{ template<class Cost=ll> struct tree { int n; int root; vector<int> par; // par[i]: dfs木における親 vector<Edge<Cost>*> edge; // edge[i]: dfs木における親への辺のpointer vector<int> dfstrv; // dfstrv[i]: dfs木でi番目に訪れるノード。dpはこれを逆順に回す vector<int> ord; // ord[u]: uのdfs木における訪問順 vector<int> end; // end[u]: uのdfs終了時のカウンター vector<int> psize; // psize[u]: uのpartial tree size // uの部分木は[ord[u], end[u]) // ordとdfstrvは逆変換 vector<int> depth; // depth[i]: dfs木でのiの深さ vector<Cost> ldepth; // ldepth[i]: dfs木でのrootからの距離 vector<vector<Edge<Cost>>> adj_list; // 辺(隣接リスト) auto operator[](int pos) const { return adj_list[pos]; } vector<vector<int>> children; vector<int> euler_tour; vector<int> et_fpos; // euler_tour first occurence position SegmentTree<int> _seg; // seg(map(ord, euler_tour), mymin, 1e18) vector<int> head_of_comp; int _counter = 0; tree(){};/*{{{*/ tree(int n_) : n(n_), par(n_), edge(n_), ord(n_), end(n_), psize(n_), depth(n_), ldepth(n_), adj_list(n_), children(n_), et_fpos(n_), head_of_comp(n_){};/*}}}*/ void add_edge(int u, int v, Cost cost, int idx=-1) { /*{{{*/ adj_list[u].emplace_back(u, v, cost, idx); adj_list[v].emplace_back(v, u, cost, idx); } /*}}}*/ void add_edge(int u, int v) { /*{{{*/ adj_list[u].emplace_back(u, v, 1, -1); adj_list[v].emplace_back(v, u, 1, -1); } /*}}}*/ void build(int _root) { /*{{{*/ root = _root; _counter = 0; par[root] = -1; edge[root] = nullptr; _dfs_psize(root, -1); _dfs_tree(root, -1, root); _dfs_et(root); vector<int> ini(2 * n - 1); rep(i, 2 * n - 1) ini[i] = ord[euler_tour[i]]; _seg = SegmentTree<int>( ini, [](auto a, auto b) { return min(a, b); }, numeric_limits<int>().max()); } /*}}}*/ int _dfs_psize(int u, int pre) { /*{{{*/ psize[u] = 1; each(e, adj_list[u]) { if (e.to == pre) continue; psize[u] += _dfs_psize(e.to, u); } return psize[u]; } /*}}}*/ void _dfs_tree(int u, int pre, int head_node) { /*{{{*/ dfstrv.pb(u); ord[u] = _counter; if (pre != -1) { depth[u] = depth[pre] + 1; ldepth[u] = ldepth[pre] + edge[u]->cost; } _counter++; { // set most heavy child to top int max_psize = 0; int most_heavy_i = -1; for(int i = 0; i < sz(adj_list[u]); ++i) { if (adj_list[u][i].to == pre) continue; if (psize[adj_list[u][i].to] > max_psize) { most_heavy_i = i; max_psize = psize[adj_list[u][i].to]; } } if (most_heavy_i != -1) swap(adj_list[u][most_heavy_i], adj_list[u][0]); } head_of_comp[u] = head_node; rep(i, sz(adj_list[u])) { int v = adj_list[u][i].to; if (v == pre) continue; children[u].pb(v); par[v] = u; edge[v] = &adj_list[u][i]; if (i == 0) _dfs_tree(v, u, head_node); // continue components else _dfs_tree(v, u, v); // new } end[u] = _counter; } /*}}}*/ void _dfs_et(int u) { /*{{{*/ et_fpos[u] = (int)euler_tour.size(); euler_tour.pb(u); each(v, children[u]) { _dfs_et(v); euler_tour.pb(u); } } /*}}}*/ bool is_leaf(int u) { return children[u].size() == 0; } int lca(int u, int v) { /*{{{*/ if (u == v) return u; if (et_fpos[u] > et_fpos[v]) swap(u, v); return dfstrv[_seg.query(et_fpos[u], et_fpos[v])]; } /*}}}*/ int dist(int u, int v) { /*{{{*/ int p = lca(u, v); return depth[u] + depth[v] - 2 * depth[p]; } /*}}}*/ Cost ldist(int u, int v) { // length dist{{{ int p = lca(u, v); return ldepth[u] + ldepth[v] - 2 * ldepth[p]; } /*}}}*/ pair<int, int> diameter() { /*{{{*/ int u, v; Cost max_len = *max_element(all(ldepth)); rep(i, n) { if (ldepth[i] == max_len) { u = i; break; } } Cost md = -1; rep(i, n) { Cost d = ldist(u, i); if (d > md) { v = i; md = d; } } return mp(u, v); } /*}}}*/ vector<pair<int, int>> hld_path(int u, int v, bool for_edge=true) { //{{{ // return {[l0, r0), [l1, r1), ....} for_edge=trueでlcaは除いて返すことに注意。 vector<pair<int, int>> res; while (head_of_comp[u] != head_of_comp[v]) { if (depth[head_of_comp[u]] < depth[head_of_comp[v]]) { res.push_back({ord[head_of_comp[v]], ord[v]+1}); v = par[head_of_comp[v]]; } else { res.push_back({ord[head_of_comp[u]], ord[u]+1}); u = par[head_of_comp[u]]; } } res.push_back({min(ord[u], ord[v]) + (for_edge?1:0), max(ord[u], ord[v])+1}); return res; } //}}} #if defined(PCM) || defined(LOCAL) /*{{{*/ friend ostream& operator<<(ostream& os, const tree& tr) { os << endl; os << "par: " << tr.par << endl; os << "dfstrv: " << tr.dfstrv << endl; os << "ord: " << tr.ord << endl; os << "end: " << tr.end << endl; os << "depth: " << tr.depth << endl; os << "children: " << tr.children << endl; os << "euler_tour: " << tr.euler_tour << endl; os << "et_fpos: " << tr.et_fpos << endl; os << "head_of_comp:" << tr.head_of_comp << endl; return os; } #endif /*}}}*/ }; // snippet:tree }}} // snippet:Graph {{{ template<class Cost=ll> struct Graph { using Pos = int; // int以外には対応しない。 int n; // 頂点数 vector<vector<Edge<Cost>>> adj_list; auto operator[](Pos pos) const { return adj_list[pos]; } vector<Edge<Cost>> edges; tree<Cost> tr; Pos root; vector<int> _used_in_dfs; vector<int> lowlink; Cost zerocost; Cost infcost; Graph() {} Graph(int _n) : n(_n), adj_list(_n), tr(n), _used_in_dfs(n), zerocost(0LL), infcost(inf<Cost>) { } Graph(int _n, Cost zc, Cost ic) : n(_n), adj_list(_n), tr(n), _used_in_dfs(n), zerocost(zc), infcost(ic) { } void add_edge(Pos from, Pos to, Cost cost, int idx=-1) {/*{{{*/ adj_list[from].emplace_back(from, to, cost, idx); edges.emplace_back(from, to, cost, idx); } void add_edge(Pos from, Pos to) { // for ll adj_list[from].emplace_back(from, to, 1, -1); edges.emplace_back(from, to, 1, -1); }/*}}}*/ void build_tree(Pos _root) {/*{{{*/ root = _root; _dfs_tree(root); tr.build(root); _make_lowlink(); }/*}}}*/ vector<int> make_bipartite() {/*{{{*/ union_find buf(2 * n); rep(u, n) { each(e, adj_list[u]) { buf.merge(u, e.to + n); buf.merge(e.to, u + n); } } vector<int> res(n, -1); rep(u, n) { if (buf.same(u, u + n)) return res; } rep(u, n) { if (buf.same(0, u)) res[u] = 0; else res[u] = 1; } return res; }/*}}}*/ void _dfs_tree(Pos u) {/*{{{*/ _used_in_dfs[u] = 1; each(e, adj_list[u]) { if (_used_in_dfs[e.to]) continue; tr.add_edge(u, e.to, e.cost); _dfs_tree(e.to); } }/*}}}*/ void _make_lowlink() {/*{{{*/ lowlink = vector<Pos>(n, numeric_limits<Pos>().max()); r_rep(i, n) { Pos u = tr.dfstrv[i]; chmin(lowlink[u], tr.ord[u]); each(e, adj_list[u]) { if (e.to == tr.par[u]) continue; else if (tr.ord[e.to] < tr.ord[u]) { chmin(lowlink[u], tr.ord[e.to]); } else { chmin(lowlink[u], lowlink[e.to]); } } } }/*}}}*/ vector<Pos> get_articulation_points() {/*{{{*/ if (sz(lowlink) == 0) throw("make_lowlik() beforehand"); vector<Pos> res; if (sz(tr.children[root]) > 1) { res.push_back(root); } rep(u, 0, n) { if (u == root) continue; bool is_kan = false; each(v, tr.children[u]) { if (tr.ord[u] <= lowlink[v]) { is_kan = true; } } if (is_kan) res.push_back(u); } return res; }/*}}}*/ vector<Edge<Cost>> get_bridges() {/*{{{*/ if (sz(lowlink) == 0) throw("make_lowlik() beforehand"); vector<Edge<Cost>> res; each(edge, edges){ if (tr.ord[edge.from] < lowlink[edge.to]) res.push_back(edge); } return res; }/*}}}*/ vector<Edge<Cost>> kruskal_tree() {/*{{{*/ // 使用される辺のvectorを返す vector<Edge<Cost>> res(n - 1); sort(all(edges), [&](auto l, auto r) { return l.cost < r.cost; }); union_find uf(n); Cost total_cost = zerocost; int idx = 0; each(e, edges) { if (uf.same(e.from, e.to)) continue; uf.merge(e.from, e.to); total_cost = total_cost + e.cost; res[idx] = e; idx++; } assert(idx == n - 1); return res; }/*}}}*/ vector<Cost> dijkstra(vector<Pos> starts) { // 多点スタート{{{ vector<Cost> dist(n, infcost); // 最短距離 PQ<pair<Cost, Pos>> pq; each(start, starts) { dist[start] = zerocost; pq.push(make_pair(zerocost, start)); } while (!pq.empty()) { auto cp = pq.top(); pq.pop(); auto [cost, u] = cp; if (cost > dist[u]) continue; for (const auto& edge : adj_list[u]) { Cost new_cost = cost + edge.cost; // TODO: 問題によってはここが変更の必要あり if (new_cost < dist[edge.to]) { dist[edge.to] = new_cost; pq.push(make_pair(new_cost, edge.to)); } } } return dist; };/*}}}*/ vector<Cost> dijkstra(Pos start) { // 1点スタート{{{ vector<Pos> starts = {start}; return dijkstra(starts); };/*}}}*/ }; // snippet:Graph }}} int solve() { // grid graphを通常のグラフに格納する。 int h, m; cin >> h >> m; int w = h; int n = h * w; // 頂点数 vector<vector<ll>> cost(h, vector<ll>(w)); rep(i, m) { int h,w;cin>>h>>w; int c;cin>>c; h--;w--; cost[h][w] = c; } Graph g(2*n); auto nid = [&](int i, int j){return (i*w + j);}; // int u = nid(i, j); auto pos = [&](int u) -> pair<int, int> { return {u/w, u%w}; }; // auto [i,j] = pos(u); int dx[] = {1, -1, 0, 0}; int dy[] = {0, 0, 1, -1}; rep(i, h) rep(j, w) { rep(dir, 4) { int ni = i + dx[dir]; int nj = j + dy[dir]; if (is_in(ni, 0, h) && is_in(nj, 0, w)) { g.add_edge(nid(i, j), nid(ni, nj), cost[ni][nj]+1); g.add_edge(nid(i, j), nid(ni, nj)+n, 1); g.add_edge(nid(i, j)+n, nid(ni, nj)+n, cost[ni][nj]+1); } } } auto d = g.dijkstra(0); cout << d[nid(h-1, w-1) + n] << endl; return 0; } int main(){/*{{{*/ solve(); #if defined(PCM) || defined(LOCAL) check_input(); #endif return 0; }/*}}}*/