//generated by ChatGPT #include using namespace std; using int64 = long long; // コンパイル時に -DHEURISTIC_K=500 などで変更可能 #ifndef HEURISTIC_K #define HEURISTIC_K 2000 #endif /* * v の中から * 1. 配列中央に近い HEURISTIC_K 個 * 2. 値が大きい HEURISTIC_K 個 * を候補として選ぶ。 */ static vector choose_candidates(const vector& v) { const int n = static_cast(v.size()); const int take = min(n, HEURISTIC_K); vector selected(n, false); vector order(n); iota(order.begin(), order.end(), 0); // 2倍した中央からの距離。 // abs(i - (n-1)/2) の小数を避けたもの。 auto center_distance = [n](int i) { return abs(2 * i - (n - 1)); }; // 中央に近い順 sort(order.begin(), order.end(), [&](int i, int j) { int di = center_distance(i); int dj = center_distance(j); if (di != dj) return di < dj; if (v[i] != v[j]) return v[i] > v[j]; return i < j; }); for (int t = 0; t < take; ++t) { selected[order[t]] = true; } // 値が大きい順 sort(order.begin(), order.end(), [&](int i, int j) { if (v[i] != v[j]) return v[i] > v[j]; int di = center_distance(i); int dj = center_distance(j); if (di != dj) return di < dj; return i < j; }); for (int t = 0; t < take; ++t) { selected[order[t]] = true; } return selected; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; cin >> T; while (T--) { int N, M; cin >> N >> M; vector A(N), B(M); vector C(N), D(M); for (int64& x : A) cin >> x; for (int64& x : B) cin >> x; for (int& x : C) cin >> x; for (int& x : D) cin >> x; vector prefixA(N + 1, 0); vector prefixB(M + 1, 0); for (int i = 0; i < N; ++i) { prefixA[i + 1] = prefixA[i] + A[i]; } for (int j = 0; j < M; ++j) { prefixB[j + 1] = prefixB[j] + B[j]; } vector radiusA(N); vector radiusB(M); for (int i = 0; i < N; ++i) { radiusA[i] = min(i, N - 1 - i); } for (int j = 0; j < M; ++j) { radiusB[j] = min(j, M - 1 - j); } vector candidateA = choose_candidates(A); vector candidateB = choose_candidates(B); const int colorCount = N + M; vector> positionsA(colorCount + 1); vector> positionsB(colorCount + 1); for (int i = 0; i < N; ++i) { positionsA[C[i]].push_back(i); } for (int j = 0; j < M; ++j) { positionsB[D[j]].push_back(j); } int64 answer = -1; auto evaluate = [&](int i, int j) { int radius = min(radiusA[i], radiusB[j]); int64 sumA = prefixA[i + radius + 1] - prefixA[i - radius]; int64 sumB = prefixB[j + radius + 1] - prefixB[j - radius]; answer = max(answer, sumA + sumB); }; /* * A の候補中心 × B の同色な全中心 */ for (int i = 0; i < N; ++i) { if (!candidateA[i]) continue; for (int j : positionsB[C[i]]) { evaluate(i, j); } } /* * B の候補中心 × A の同色な全中心 * * candidateA[i] も真の場合、その組は上で評価済みなので * 重複を避けるため除外する。 */ for (int j = 0; j < M; ++j) { if (!candidateB[j]) continue; for (int i : positionsA[D[j]]) { if (candidateA[i]) continue; evaluate(i, j); } } cout << answer << '\n'; } return 0; }