Submission #991214

#TimeUsernameProblemLanguageResultExecution timeMemory
991214model_codeRoad Service 2 (JOI24_ho_t5)C++17
100 / 100
933 ms297300 KiB
#include <iostream> #include <queue> #include <vector> #include <algorithm> using namespace std; #pragma warning (disable: 4996) // ==================================================================================================================================================== その他の関数 // 位置 pos から x 手で移動できる最大位置 int GetMaxPosition(int pos, int x, vector<vector<int>>& par) { if (x == -1) return -50000; vector<int> dp0(23, -1); vector<int> dp1(23, -1); dp0[22] = pos; for (int i = 21; i >= 0; i--) { if ((x / (1 << i)) % 2 == 0) { dp0[i] = dp0[i + 1]; dp1[i] = dp1[i + 1]; continue; } if (dp0[i + 1] != -1) dp0[i] = max(dp0[i], par[3 * i + 1][dp0[i + 1]]); if (dp1[i + 1] != -1) dp0[i] = max(dp0[i], par[3 * i + 0][dp1[i + 1]]); if (dp0[i + 1] != -1) dp1[i] = max(dp1[i], par[3 * i + 2][dp0[i + 1]]); if (dp1[i + 1] != -1) dp1[i] = max(dp1[i], par[3 * i + 1][dp1[i + 1]]); } return dp0[0]; } // 位置 pos から位置 goal 以上まで行くための最小コスト int GetMinCost(int pos, int goal, vector<vector<int>>& par) { if (pos == -1) return 1000000000; if (pos >= goal) return 0; int cur1 = pos; int cur2 = -1; int ans = 0; for (int i = 21; i >= 0; i--) { int v1 = -1; int v2 = -1; if (cur1 != -1) v1 = max(v1, par[3 * i + 1][cur1]); if (cur2 != -1) v1 = max(v1, par[3 * i + 0][cur2]); if (cur1 != -1) v2 = max(v2, par[3 * i + 2][cur1]); if (cur2 != -1) v2 = max(v2, par[3 * i + 1][cur2]); if (v1 < goal && v2 < goal) { cur1 = v1; cur2 = v2; ans += (1 << i); } } if (cur1 != -1 && par[1][cur1] >= goal) return ans + 1; if (cur2 != -1 && par[1][cur2] >= goal) return ans + 2; if (cur1 != -1 && par[2][cur1] >= goal) return ans + 2; return ans + 3; } // 極小な区間だけを取り出す関数 vector<pair<int, int>> OnlyMinimal(vector<pair<int, int>> Ranges) { for (int i = 0; i < Ranges.size(); i++) Ranges[i].first *= -1; sort(Ranges.begin(), Ranges.end()); vector<pair<int, int>> Return; int MinValue = (1 << 30); for (int i = 0; i < Ranges.size(); i++) { if (MinValue > Ranges[i].second) { MinValue = Ranges[i].second; Return.push_back(Ranges[i]); } } for (int i = 0; i < Return.size(); i++) Return[i].first *= -1; sort(Return.begin(), Return.end()); return Return; } // 位置 pos を区間 [cl, cr] に修正 pair<int, int> FixPosition(int moto, int pos, int cl, int cr, int cost, vector<int>& C, vector<int>& NextCost1, vector<int>& NextCost2, vector<vector<int>>& par, vector<int>& UpLim) { if (pos < cl) return make_pair(-1, 1000000000); if (pos <= cr) return make_pair(pos, cost); if (C[pos] == 1) { int idx1 = NextCost1[cr]; int idx2 = NextCost2[cr]; int result = -1; if (idx1 >= cl) result = max(result, idx1); if (cost >= 2) { int prepos = GetMaxPosition(moto, cost - 2, par); int nexpos = UpLim[prepos]; if (nexpos >= cl && NextCost2[min(cr, nexpos)] >= cl) result = max(result, NextCost2[min(cr, nexpos)]); } if (result != -1) return make_pair(result, cost); return make_pair(idx2, cost + 1); } return make_pair(NextCost2[cr], cost); } // 位置 pos から区間 [cl, cr] に行くための最小コスト int RangeCost(int pos, int cl, int cr, vector<int>& C, vector<int>& NextCost1, vector<int>& NextCost2, vector<vector<int>>& par, vector<int>& UpLim) { int base = GetMinCost(pos, cl, par); int newpos = GetMaxPosition(pos, base, par); pair<int, int> fixpos = FixPosition(pos, newpos, cl, cr, base, C, NextCost1, NextCost2, par, UpLim); return fixpos.second; } // ==================================================================================================================================================== 問題を解く関数 vector<int> solve_subtask8(int H, int W, int Q, vector<vector<char>> A, vector<vector<char>> B, vector<int> C, vector<vector<pair<int, int>>> Query) { // Step 1. 連結成分を探す vector<vector<int>> GroupID(H, vector<int>(W, -1)); int GroupCnt = 0; for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { if (GroupID[i][j] != -1) continue; queue<pair<int, int>> Que; Que.push(make_pair(i, j)); GroupID[i][j] = GroupCnt; while (!Que.empty()) { int px = Que.front().first; int py = Que.front().second; Que.pop(); if (px - 1 >= 0 && B[px - 1][py] == '1' && GroupID[px - 1][py] == -1) { GroupID[px - 1][py] = GroupCnt; Que.push(make_pair(px - 1, py)); } if (px + 1 < H && B[px][py] == '1' && GroupID[px + 1][py] == -1) { GroupID[px + 1][py] = GroupCnt; Que.push(make_pair(px + 1, py)); } if (py - 1 >= 0 && A[px][py - 1] == '1' && GroupID[px][py - 1] == -1) { GroupID[px][py - 1] = GroupCnt; Que.push(make_pair(px, py - 1)); } if (py + 1 < W && A[px][py] == '1' && GroupID[px][py + 1] == -1) { GroupID[px][py + 1] = GroupCnt; Que.push(make_pair(px, py + 1)); } } GroupCnt += 1; } } // Step 2. 各連結成分に対応する区間を求める vector<pair<int, int>> Range(GroupCnt, make_pair(100000000, -100000000)); for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { Range[GroupID[i][j]].first = min(Range[GroupID[i][j]].first, i); Range[GroupID[i][j]].second = max(Range[GroupID[i][j]].second, i); } } // Step 3. 各地点の直前のコスト 1, 2 の位置を計算 vector<int> NextCost1(H, -1); vector<int> NextCost2(H, -1); for (int i = 0; i < H; i++) { if (i >= 1) { NextCost1[i] = NextCost1[i - 1]; NextCost2[i] = NextCost2[i - 1]; } if (C[i] == 1) NextCost1[i] = i; if (C[i] == 2) NextCost2[i] = i; } // Step 4. 最大値を計算 vector<int> UpLim(H, -1); for (int i = 0; i < H; i++) UpLim[i] = i; for (pair<int, int> idx : Range) { UpLim[idx.first] = max(UpLim[idx.first], idx.second); } for (int i = 1; i < H; i++) UpLim[i] = max(UpLim[i], UpLim[i - 1]); // Step 5. ダブリングの初期化 // par[3*d+e][i] ã¯é ‚ç‚¹ i からコスト 2^d+(e-1) でどこまで行けるか vector<vector<int>> par(66, vector<int>(H, -1)); for (int i = 0; i < H; i++) par[0][i] = i; for (int i = 0; i < H; i++) par[1][i] = max(i, NextCost1[UpLim[i]]); for (int i = 0; i < H; i++) { int v1 = NextCost2[UpLim[i]]; int v2 = NextCost1[UpLim[i]]; int v3 = (v2 == -1 ? -1 : NextCost1[UpLim[v2]]); par[2][i] = max({ i, v1, v3 }); } // Step 6. ダブリングの計算 for (int d = 3; d < 66; d += 3) { for (int i = 0; i < H; i++) { par[d + 0][i] = max({ par[d - 3][par[d - 2][i]], par[d - 2][par[d - 3][i]] }); par[d + 1][i] = max({ par[d - 3][par[d - 1][i]], par[d - 2][par[d - 2][i]], par[d - 1][par[d - 3][i]] }); par[d + 2][i] = max({ par[d - 2][par[d - 1][i]], par[d - 1][par[d - 2][i]] }); } } // Step 7. 各クエリにおける答えを計算 vector<int> Answer(Q, -1); for (int t = 0; t < Q; t++) { vector<int> Groups; for (pair<int, int> idx : Query[t]) Groups.push_back(GroupID[idx.first][idx.second]); sort(Groups.begin(), Groups.end()); Groups.erase(unique(Groups.begin(), Groups.end()), Groups.end()); if (Groups.size() == 1) { Answer[t] = 0; } else { vector<pair<int, int>> List; for (int idx : Groups) List.push_back(Range[idx]); vector<pair<int, int>> Important = OnlyMinimal(List); vector<int> dpval(Important.size(), 1000000000); vector<int> dp0(Important.size(), -1); vector<int> dp1(Important.size(), -1); // 初期値の計算 if (NextCost1[Important[0].second] < Important[0].first) { dpval[0] = 2; dp0[0] = NextCost2[Important[0].second]; dp1[0] = -1; } else { dpval[0] = 1; dp0[0] = NextCost1[Important[0].second]; if (dp0[0] < Important[0].first) dp0[0] = -1; dp1[0] = NextCost2[Important[0].second]; if (dp1[0] < Important[0].first) dp1[0] = -1; } // 動的計画法 for (int i = 1; i < Important.size(); i++) { int cl = Important[i].first; int cr = Important[i].second; int cost1 = 1000000000; if (dp0[i - 1] != -1) cost1 = RangeCost(dp0[i - 1], cl, cr, C, NextCost1, NextCost2, par, UpLim); int cost2 = 1000000000; if (dp1[i - 1] != -1) cost2 = RangeCost(dp1[i - 1], cl, cr, C, NextCost1, NextCost2, par, UpLim); dpval[i] = min({ dpval[i], dpval[i - 1] + cost1, dpval[i - 1] + cost2 + 1 }); if (dpval[i] > 2 * H) break; int pos1 = GetMaxPosition(dp0[i - 1], dpval[i] - (dpval[i - 1] + 0) + 0, par); int pos2 = GetMaxPosition(dp1[i - 1], dpval[i] - (dpval[i - 1] + 1) + 0, par); int pos3 = GetMaxPosition(dp0[i - 1], dpval[i] - (dpval[i - 1] + 0) + 1, par); int pos4 = GetMaxPosition(dp1[i - 1], dpval[i] - (dpval[i - 1] + 1) + 1, par); pair<int, int> fix1 = FixPosition(dp0[i - 1], pos1, cl, cr, dpval[i] - (dpval[i - 1] + 0) + 0, C, NextCost1, NextCost2, par, UpLim); pair<int, int> fix2 = FixPosition(dp1[i - 1], pos2, cl, cr, dpval[i] - (dpval[i - 1] + 1) + 0, C, NextCost1, NextCost2, par, UpLim); pair<int, int> fix3 = FixPosition(dp0[i - 1], pos3, cl, cr, dpval[i] - (dpval[i - 1] + 0) + 1, C, NextCost1, NextCost2, par, UpLim); pair<int, int> fix4 = FixPosition(dp1[i - 1], pos4, cl, cr, dpval[i] - (dpval[i - 1] + 1) + 1, C, NextCost1, NextCost2, par, UpLim); if (fix1.second + (dpval[i - 1] + 0) == dpval[i] + 0) dp0[i] = max(dp0[i], fix1.first); if (fix1.second + (dpval[i - 1] + 0) == dpval[i] + 1) dp1[i] = max(dp1[i], fix1.first); if (fix2.second + (dpval[i - 1] + 1) == dpval[i] + 0) dp0[i] = max(dp0[i], fix2.first); if (fix2.second + (dpval[i - 1] + 1) == dpval[i] + 1) dp1[i] = max(dp1[i], fix2.first); if (fix3.second + (dpval[i - 1] + 0) == dpval[i] + 0) dp0[i] = max(dp0[i], fix3.first); if (fix3.second + (dpval[i - 1] + 0) == dpval[i] + 1) dp1[i] = max(dp1[i], fix3.first); if (fix4.second + (dpval[i - 1] + 1) == dpval[i] + 0) dp0[i] = max(dp0[i], fix4.first); if (fix4.second + (dpval[i - 1] + 1) == dpval[i] + 1) dp1[i] = max(dp1[i], fix4.first); } Answer[t] = dpval[Important.size() - 1]; if (Answer[t] > 2 * H) Answer[t] = -1; } } // Step 8. 答えを返す return Answer; } // ==================================================================================================================================================== 入出力 int main() { // 入力 int H, W, Q; scanf("%d%d%d", &H, &W, &Q); vector<vector<char>> A(H, vector<char>(W - 1, 0)); vector<vector<char>> B(H - 1, vector<char>(W, 0)); vector<vector<pair<int, int>>> Query(Q, vector<pair<int, int>>(0, make_pair(0, 0))); vector<int> C(H, 0); for (int i = 0; i < H; i++) { for (int j = 0; j < W - 1; j++) cin >> A[i][j]; } for (int i = 0; i < H - 1; i++) { for (int j = 0; j < W; j++) cin >> B[i][j]; } for (int i = 0; i < H; i++) cin >> C[i]; for (int i = 0; i < Q; i++) { int t, x, y; scanf("%d", &t); for (int j = 0; j < t; j++) { scanf("%d%d", &x, &y); x--; y--; Query[i].push_back(make_pair(x, y)); } } // 出力 vector<int> Answer = solve_subtask8(H, W, Q, A, B, C, Query); for (int i = 0; i < Q; i++) printf("%d\n", Answer[i]); return 0; }

Compilation message (stderr)

Main.cpp:6: warning: ignoring '#pragma warning ' [-Wunknown-pragmas]
    6 | #pragma warning (disable: 4996)
      | 
Main.cpp: In function 'std::vector<std::pair<int, int> > OnlyMinimal(std::vector<std::pair<int, int> >)':
Main.cpp:57:20: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::pair<int, int> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   57 |  for (int i = 0; i < Ranges.size(); i++) Ranges[i].first *= -1;
      |                  ~~^~~~~~~~~~~~~~~
Main.cpp:61:20: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::pair<int, int> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   61 |  for (int i = 0; i < Ranges.size(); i++) {
      |                  ~~^~~~~~~~~~~~~~~
Main.cpp:67:20: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::pair<int, int> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   67 |  for (int i = 0; i < Return.size(); i++) Return[i].first *= -1;
      |                  ~~^~~~~~~~~~~~~~~
Main.cpp: In function 'std::vector<int> solve_subtask8(int, int, int, std::vector<std::vector<char> >, std::vector<std::vector<char> >, std::vector<int>, std::vector<std::vector<std::pair<int, int> > >)':
Main.cpp:217:22: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::pair<int, int> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  217 |    for (int i = 1; i < Important.size(); i++) {
      |                    ~~^~~~~~~~~~~~~~~~~~
Main.cpp: In function 'int main()':
Main.cpp:254:7: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  254 |  scanf("%d%d%d", &H, &W, &Q);
      |  ~~~~~^~~~~~~~~~~~~~~~~~~~~~
Main.cpp:267:21: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  267 |   int t, x, y; scanf("%d", &t);
      |                ~~~~~^~~~~~~~~~
Main.cpp:269:9: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  269 |    scanf("%d%d", &x, &y); x--; y--;
      |    ~~~~~^~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...