#include using namespace std; using int64 = long long; // total <= current * 2^k を満たす最小の k。 // total, current は正。 int doublingCount(int64 total, int64 current) { if (total <= current) { return 0; } // ceil(total / current) - 1 unsigned long long x = static_cast((total - 1) / current); return 64 - __builtin_clzll(x); } // 向かい合う2台の最小操作回数。 // 左の移動距離 left、右の移動距離 right、目的配置の間隔 gap。 int64 solvePair(int64 left, int64 right, int64 gap) { const int64 total = left + gap + right; int64 answer = numeric_limits::max(); int steps = 0; int64 width = gap; int64 blocks = 0; while (width <= total) { auto evaluate = [&](int64 l, int64 r) { // 幅を steps 回倍増した後、 // 左へ q * gap、右へ (blocks - q) * gap 広がっている。 // // 右端が初期位置を越えないための下限。 int64 q = max(0, blocks - r / gap); // 次の1回で左端を初期位置へ到達させるための下限。 if (l > width) { int64 need = (l - width + gap - 1) / gap; q = max(q, need); } if (q > blocks) { return; } int64 expandedLeft = q * gap; if (expandedLeft > l) { return; } int64 remainingLeft = l - expandedLeft; if (remainingLeft > width) { return; } int64 newWidth = width + remainingLeft; int64 candidate = steps; if (remainingLeft > 0) { ++candidate; } candidate += doublingCount(total, newWidth); answer = min(answer, candidate); }; // 左端を先に到達させる。 evaluate(left, right); // 右端を先に到達させる。 evaluate(right, left); width *= 2; blocks = blocks * 2 + 1; ++steps; } return answer; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int Q; cin >> Q; while (Q--) { int64 N; int M; cin >> N >> M; vector S(M), G(M); for (int i = 0; i < M; ++i) { cin >> S[i]; } for (int i = 0; i < M; ++i) { cin >> G[i]; } vector> elevators(M); for (int i = 0; i < M; ++i) { elevators[i] = {S[i], G[i]}; } sort(elevators.begin(), elevators.end()); for (int i = 0; i < M; ++i) { S[i] = elevators[i].first; G[i] = elevators[i].second; } bool possible = true; for (int i = 1; i < M; ++i) { if (G[i - 1] > G[i]) { possible = false; break; } // 同じ階への合流はできない。 // 同じ目的階を持つなら、両方とも最初からその階にいる必要がある。 if (G[i - 1] == G[i]) { if (S[i - 1] != G[i - 1] || S[i] != G[i]) { possible = false; break; } } } if (!possible) { cout << -1 << '\n'; continue; } int64 answer = 0; for (int i = 0; i < M;) { if (S[i] == G[i]) { ++i; continue; } if (S[i] < G[i]) { // 右へ動く。 if (i + 1 < M && S[i + 1] > G[i + 1]) { // 右隣が左へ動くので、2台をまとめて処理。 int64 left = G[i] - S[i]; int64 right = S[i + 1] - G[i + 1]; int64 gap = G[i + 1] - G[i]; answer += solvePair(left, right, gap); i += 2; } else { if (i + 1 == M) { // 右側にエレベーターがいない。 ++answer; } else { int64 initialGap = G[i + 1] - S[i]; int64 targetGap = G[i + 1] - G[i]; answer += doublingCount(initialGap, targetGap); } ++i; } } else { // 左へ動く。 // 左隣と向かい合う組なら、すでに組として処理されている。 if (i == 0) { ++answer; } else { int64 initialGap = S[i] - G[i - 1]; int64 targetGap = G[i] - G[i - 1]; answer += doublingCount(initialGap, targetGap); } ++i; } } cout << answer << '\n'; } return 0; }