熱門文章

2026年5月24日 星期日

ZeroJudge 解題筆記:e457. 也是 Segment Tree 練習

作者:王一哲
日期:2026年5月24日


ZeroJudge 題目連結:e457. 也是 Segment Tree 練習

解題想法


單點修改,查詢區間連乘的正負號,不需要真的存數字,如果數字大於 0 存 1,等於 0 存 0,小於 0 存 -1。

Python 程式碼


使用時間約為 1.1 s,記憶體約為 33.9 MB,通過測試。
class SegmentTree:
    def __init__(self, data):
        self.n = len(data)
        self.data = [0]
        for d in data:
            if d > 0:
                self.data.append(1)
            elif d == 0:
                self.data.append(0)
            else:
                self.data.append(-1)
        self.tree = [0]*(4 * self.n)
        if self.n > 0:
            self._build(0, 1, self.n)
    
    # --- 內部遞迴函式 ---
    def _build(self, node, start, end):
        if start == end:
            if self.data[start] > 0:
                self.tree[node] = 1
            elif self.data[start] == 0:
                self.tree[node] = 0
            else:
                self.tree[node] = -1
            return

        mid = (end - start) // 2 + start
        self._build(2*node + 1, start, mid)
        self._build(2*node + 2, mid + 1, end)
        self.tree[node] = self.tree[2*node + 1] * self.tree[2*node + 2]

    def _update(self, node, start, end, target, val):
        if start == end:
            if val > 0:
                self.tree[node] = 1
                self.data[target] = 1
            elif val == 0:
                self.tree[node] = 0
                self.data[target] = 0
            else:
                self.tree[node] = -1
                self.data[target] = -1
            return

        mid = (end - start) // 2 + start
        if target <= mid:
            self._update(2*node + 1, start, mid, target, val)
        else:
            self._update(2*node + 2, mid + 1, end, target, val)
        self.tree[node] = self.tree[2*node + 1] * self.tree[2*node + 2]

    def _query(self, node, start, end, left, right):
        if end < left or start > right:
            return 1
        if left <= start and right >= end:
            return self.tree[node]
        mid = (end - start) // 2 + start
        lval = self._query(2*node + 1, start, mid, left, right)
        rval = self._query(2*node + 2, mid + 1, end, left, right)
        return lval * rval
    
    # --- 外部呼叫函式 ---
    def update(self, target, val):
        self._update(0, 1, self.n, target, val)

    def query(self, left, right):
        return self._query(0, 1, self.n, left, right)

def solve():
    import sys

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])
        k = int(data[ptr+1])
        ptr += 2
        nums = list(map(int, data[ptr:ptr+n]))
        ptr += n
        st = SegmentTree(nums)
        for i in range(k):
            op = data[ptr]
            x = int(data[ptr+1])
            y = int(data[ptr+2])
            ptr += 3
            if op == "C":
                st.update(x, y)
            else:
                z = st.query(x, y)
                if z == 1:
                    result.append("+")
                elif z == 0:
                    result.append("0")
                else:
                    result.append("-")
        result.append("\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月23日 星期六

ZeroJudge 解題筆記:e437. Segment Tree 練習2 + 區間修改

作者:王一哲
日期:2026年5月23日


ZeroJudge 題目連結:e437. Segment Tree 練習2 + 區間修改

解題想法


這題我只有寫 C++ 線段樹版本。

C++ 程式碼


線段樹,使用時間約為 80 ms,記憶體約為 45 MB,通過測試。
#include <cstdio>
#include <vector>
#include <utility>
#include <algorithm>
typedef long long LL;
using namespace std;

struct QueryResult {  // 回傳查詢結果用的結構體
    LL sum_val;
    int max_val, min_val;
};

/* 本題重點,自訂線段樹類別,區間更新,記錄區間加總、最大值、最小值 */
class SegmentTree {
private:
    int n, mod;
    vector<int> data, imax, imin, lazy;
    vector<LL> isum;
    vector<bool> has_lazy;
    
    /* 內部遞迴函式 */
    void _push_up(int node) {
        isum[node] = (isum[2*node + 1] + isum[2*node + 2]) % mod;
        imax[node] = max(imax[2*node + 1], imax[2*node + 2]);
        imin[node] = min(imin[2*node + 1], imin[2*node + 2]);
    }

    void _build(int node, int start, int end) {
        // 遞迴出口
        if (start == end) {
            isum[node] = data[start] % mod;
            imax[node] = data[start];
            imin[node] = data[start];
            return;
        }
        // 遞迴,處理左、右半邊
        int mid = (end - start) / 2 + start;
        _build(2*node + 1, start, mid);
        _build(2*node + 2, mid + 1, end);
        _push_up(node);
    }
    
    void _push_down(int node, int start, int end) {
        if (has_lazy[node]) {
            int mid = (end - start) / 2 + start, val = lazy[node];
            // 處理左半邊
            int left_len = mid - start + 1;
            isum[2*node + 1] = (1LL * val * left_len) % mod;
            imax[2*node + 1] = val;
            imin[2*node + 1] = val;
            lazy[2*node + 1] = val;
            has_lazy[2*node + 1] = true;
            // 處理右邊
            int right_len = end - mid;
            isum[2*node + 2] = (1LL * val * right_len) % mod;
            imax[2*node + 2] = val;
            imin[2*node + 2] = val;
            lazy[2*node + 2] = val;
            has_lazy[2*node + 2] = true;
            has_lazy[node] = false;
        }
    }

    void _update(int node, int start, int end, int left, int right, int val) {
        // 遞迴出口,[start, end] 與 [left, right] 沒有交集
        if (end < left || start > right) return;
        // 遞迴出口,[left, right] 包含 [start, end],更新 node 對應的值及標記
        if (left <= start && right >= end) {
            isum[node] = (1LL * val * (end - start + 1)) % mod;
            imax[node] = val;
            imin[node] = val;
            lazy[node] = val;
            has_lazy[node] = true;
            return;
        }
        // 先呼叫 _push_down,將標記往下傳,再用遞迴處理左、右兩半
        _push_down(node, start, end);
        int mid = (end - start) / 2 + start;
        _update(2*node + 1, start, mid, left, right, val);
        _update(2*node + 2, mid + 1, end, left, right, val);
        // 更新 node 對應的加總、最大值、最小值
        _push_up(node);
    }
    
    // 合併三個查詢功能
    QueryResult _query(int node, int start, int end, int left, int right) {
        // 遞迴出口,[start, end] 與 [left, right] 沒有交集
        if (end < left || start > right) {
            return {0, -2000000000, 2000000000};  // 0 給加總,max 給極小值,min 給極大值
        }
        // 遞迴出口,[left, right] 包含 [start, end]
        if (left <= start && right >= end) {
            return {isum[node], imax[node], imin[node]};
        }
        // 先 _push_down 再遞迴
        _push_down(node, start, end);
        int mid = (end - start) / 2 + start;
        QueryResult L = _query(2*node + 1, start, mid, left, right);
        QueryResult R = _query(2*node + 2, mid + 1, end, left, right);
        QueryResult res;
        res.sum_val = (L.sum_val + R.sum_val) % mod;
        res.max_val = max(L.max_val, R.max_val);
        res.min_val = min(L.min_val, R.min_val);
        return res;
    }

public:
    // 建構子,只計算 A[1] ~ A[N] 的最大值、最小值,不要對建 N 之後的值建立線段樹
    SegmentTree(const vector<int>& input_data, int target_n, int m) {
        data = input_data;
        n = target_n;
        mod = m;
        int tree_size = 4*n + 1;
        has_lazy.assign(tree_size, false);
        lazy.assign(tree_size, 0);
        isum.assign(tree_size, 0);
        imax.assign(tree_size, 0);
        imin.assign(tree_size, 0);
        if (n > 0) {
            _build(0, 1, n);
        }
    }

    /* 外部呼叫函式 */
    void update(int left, int right, int val) {
        _update(0, 1, n, left, right, val);
    }

    pair<int, int> query(int left, int right) {
        QueryResult res = _query(0, 1, n, left, right);
        return make_pair(res.sum_val, res.max_val - res.min_val);
    }
};

int main() {
    // 讀取測資
    int k, m, N, Q;
    scanf("%d %d", &k, &m);
    vector<int> A (k+1, 0);
    for(int i=1; i<=k; i++) {
        scanf("%d", &A[i]);
    }
    scanf("%d %d", &N, &Q);
    int limit = max(N, Q);
    A.resize(limit + 1);  // 調整 A 的長度
    // 第1個迴圈,填入 A[k+1] ~ A[limit]
    for(int i=k+1; i<=limit; i++) {
        A[i] = (A[i-2] * 97 + A[i-1] * 3) % m + 1;
    }
    // 第2個迴圈,計算 op, x, y 同時查詢或更新線段樹
    SegmentTree st(A, N, m);
    int j = limit;
    for(int i=1; i<=Q; i++) {
        bool op = A[i] & 1;
        int x = (A[i] + A[j]) % N + 1;
        int y = x + ((A[i] << 3) + (A[j] << 5) + m) % (N - x + 1);
        if (op) {  // 查詢
            auto it = st.query(x, y);
            printf("%d %d\n", it.first, it.second);
        } else {  // 更新
            int z = ((A[i] << 3) + (A[j] << 5)) % m + 1;
            st.update(x, y, z);
            //printf("%d %d %d %d\n", A[i], x, y, z);
        }
        j--;
    }
    return 0;
}


2026年5月22日 星期五

ZeroJudge 解題筆記:e409. Segment Tree 練習

作者:王一哲
日期:2026年5月22日


ZeroJudge 題目連結:e409. Segment Tree 練習

解題想法


這類型不斷地更新某個位置的值,不斷地查詢區域加總的題目,基本上都是用線段樹二元索引樹處理。用 C++ 解題兩種寫法都能過關。用 Python 解題,遞迴版的線段樹與二元索引樹都太慢,後來是用非遞迴版的線段樹才過關。

Python 程式碼


遞迴版線段樹,從測資 #4 開始超時。
import sys
sys.setrecursionlimit(10000)
# --- 本題重點,自訂線段樹類別,單點更新,記錄區間最大值、最小值 ---
class SegmentTree:
    def __init__(self, data, n):
        self.data = data
        self.n = n
        self.imax = [0] * (4*self.n + 1)
        self.imin = [0] * (4*self.n + 1)
        if self.n > 0:
            self._build(0, 1, self.n)  # 題目的 A 是 1-index
    
    # --- 內部遞迴函式 ---
    def _build(self, node, start, end):
        # 遞迴出口
        if start == end:
            self.imax[node] = self.data[start]
            self.imin[node] = self.data[start]
            return
        # 遞迴,處理左、右半邊
        mid = (end - start) // 2 + start
        self._build(2*node + 1, start, mid)
        self._build(2*node + 2, mid + 1, end)
        # 更新 node 對應的最大值、最小值
        self.imax[node] = max(self.imax[2*node + 1], self.imax[2*node + 2])
        self.imin[node] = min(self.imin[2*node + 1], self.imin[2*node + 2])
    
    def _update(self, node, start, end, target, val):
        # 遞迴出口
        if start == end:
            self.imax[node] = val
            self.imin[node] = val
            self.data[target] = val
            return
        # 遞迴,處理左、右半邊
        mid = (end - start) // 2 + start
        if target <= mid:  # 在左側
            self._update(2*node + 1, start, mid, target, val)
        else:  # 在右側
            self._update(2*node + 2, mid + 1, end, target, val)
        # 更新 node 對應的最大值、最小值
        self.imax[node] = max(self.imax[2*node + 1], self.imax[2*node + 2])
        self.imin[node] = min(self.imin[2*node + 1], self.imin[2*node + 2])
    
    def _query(self, node, start, end, left, right):
        # 遞迴出口,[start, end] 與 [left, right] 沒有交集
        if end < left or start > right:
            return (-2000000000, 2000000000)
        # 遞迴出口,[left, right] 包含 [start, end]
        if left <= start and right >= end:
            return (self.imax[node], self.imin[node])
        # 遞迴,處理左、右半邊
        mid = (end - start) // 2 + start
        L = self._query(2*node + 1, start, mid, left, right)
        R = self._query(2*node + 2, mid + 1, end, left, right)
        return (max(L[0], R[0]), min(L[1], R[1]))
        
    # --- 外部呼叫函式 ---
    def update(self, target, val):
        self._update(0, 1, self.n, target, val)

    def query(self, left, right):
        res = self._query(0, 1, self.n, left, right)
        return res[0] - res[1]

# --- 主要的解題過程 ---
def solve():
    import sys

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        MaxN, MaxQ = 1000005, 100005
        k = int(data[ptr])
        m = int(data[ptr+1])
        ptr += 2
        A = [0]*MaxN
        for i in range(1, k+1):
            A[i] = int(data[ptr])
            ptr += 1
        N = int(data[ptr])
        Q = int(data[ptr+1])
        ptr += 2
        C = [False]*MaxQ
        X = [0]*MaxQ
        Y = [0]*MaxQ

        # 題目中給定的産生資料函式
        def gen_dat():
            # 第一個迴圈
            limit = max(Q, N)
            i = k+1
            while i <= limit:
                A[i] = (A[i-2]*97 + A[i-1]*3) % m + 1
                i += 1
            # 第二個迴圈
            i = 1
            j = limit
            while i <= Q:
                C[i] = A[i] & 1
                X[i] = (A[i] + A[j]) % N + 1
                if C[i]: Y[i] = X[i]+ ( (A[i] << 3) + (A[j] << 5) + m ) % (N - X[i] + 1)
                else: Y[i] = ((A[i] << 3) + (A[j] << 5)) % m + 1
                i += 1
                j -= 1

        # 呼叫 gen_dat() 産生 A 的完整內容
        gen_dat()
        #print(A[:26])  # 印出前 26 項檢查內容
        # 讀取 operations 並輸出答案
        st = SegmentTree(A, N)
        for i in range(1, Q+1):
            op, x, y = C[i], X[i], Y[i]
            if op == 0:
                st.update(x, y)
            elif op == 1:
                result.append(f"{st.query(x, y):d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()

2026年5月21日 星期四

ZeroJudge 解題筆記:e406. Binary Indexed Tree 練習題

作者:王一哲
日期:2026年5月21日


ZeroJudge 題目連結:e406. Binary Indexed Tree 練習題

解題想法


這類型不斷地更新某個位置的值,不斷地查詢區域加總的題目,基本上都是用線段樹二元索引樹處理。用 C++ 解題兩種寫法都能過關。用 Python 解題,則會因為線段樹需要遞迴很多次,速度太慢,無法過關。

Python 程式碼


二元索引樹,使用時間約為 1.1 s,記憶體約為 73 MB,通過測試。
class FenwickTree:
    def __init__(self, A):
        self.n = len(A) - 1
        self.A = A[:]
        self.tree = A[:]
        for i in range(1, self.n + 1):
            parent_idx = i + self._lowbit(i)
            if parent_idx <= self.n:
                self.tree[parent_idx] += self.tree[i]
    
    def _lowbit(self, x):
        return x & (-x)
    
    def update(self, i, delta):
        while i <= self.n:
            self.tree[i] += delta
            i += self._lowbit(i)
    
    def update_val(self, i, val):
        delta = val - self.A[i]
        self.A[i] = val
        self.update(i, delta)
    
    def query(self, i):
        total = 0
        while i > 0:
            total += self.tree[i]
            i -= self._lowbit(i)
        return total

def solve():
    import sys
    
    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        k = int(data[ptr])
        m = int(data[ptr+1])
        ptr += 2
        A = [0] + list(map(int, data[ptr:ptr+k]))
        ptr += k
        N = int(data[ptr])
        Q = int(data[ptr+1])
        ptr += 2
        limit = max(N, Q)
        A += [0] * (limit - k + 1)  # 調整 A 的長度
        # 第1個迴圈,填入 A[k+1] ~ A[limit]
        for i in range(k+1, limit + 1):
            A[i] = (A[i-2] * 97 + A[i-1] * 3) % m + 1
        
        # 第2個迴圈,計算 op, x, y 同時查詢或更新
        bit = FenwickTree(A)
        j = limit
        for i in range(1, Q+1):
            op = A[i] & 1
            x = (A[i] + A[j]) % N + 1
            if op:  # 查詢
                y = x + ((A[i] << 3) + (A[j] << 5) + m) % (N - x + 1)
                ans = (bit.query(y) - bit.query(x-1)) % m
                result.append(f"{ans:d}\n")
            else:  # 更新
                y = ((A[i] << 3) + (A[j] << 5)) % m + 1
                bit.update_val(x, y)
            j -= 1
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月20日 星期三

ZeroJudge 解題筆記:d272. 11583 - Alien DNA

作者:王一哲
日期:2026年5月20日


ZeroJudge 題目連結:d272. 11583 - Alien DNA

解題想法


依序檢查每個 DNA 序列,取新序列與舊序列的交集,如果交集是空集合,要切一刀。

Python 程式碼


使用時間約為 0.1 s,記憶體約為 8.2 MB,通過測試。
t = int(input())  # t 組測資
for _ in range(t):  # 執行 t 次
    n = int(input())  # 這組測資有 n 個序列
    common = set(list(input()))  # 共同的鹼基字母,預設為第 1 個序列
    cut = 0  # 切幾刀
    for _ in range(1, n):  # 讀取 n-1 個序列
        dna = set(list(input()))  # 新的序列包含的鹼基字母
        common.intersection_update(dna)  # 取交集更新 common
        if not common:  # 如果 common 是空的
            cut += 1  # cut 加 1
            common = dna  # 更新 common 為 dna
    print(cut)  # 印出答案


2026年5月19日 星期二

ZeroJudge 解題筆記:d269. 11579 - Triangle Trouble

作者:王一哲
日期:2026年5月19日


ZeroJudge 題目連結:d269. 11579 - Triangle Trouble

解題想法


讀取一行測資,將 $n$ 個邊長由大到小排序,再依序讀取連續 3 個邊長 $a, b, c$,如果最長的邊 $a$ 大於等於較短的兩個邊 $b, c$ 加總,無法組成三角形;反之,用海龍公式計算三角形面積。

Python 程式碼


使用時間約為 67 ms,記憶體約為 14.4 MB,通過測試。
def solve():
    import sys

    result = []
    data = sys.stdin.read().split()
    T = int(data[0])  # T 組測資
    ptr = 1
    while ptr < len(data):  # 執行 T 次
        n = int(data[ptr])  # 首項是邊的數量
        ptr += 1
        edges = sorted(map(float, data[ptr:ptr+n]), reverse=True)  # 邊長,由大到小排序
        ptr += n
        imax = 0.0  # 最大面積
        for i in range(n-2):  # 依序讀取邊長,每次 3 項
            a, b, c = edges[i:i+3]  # 邊長
            if a >= b + c:  # 最長的邊大於等於另外兩個邊相加
                continue  # 無法組成三角形,找下一組
            s = (a + b + c) * 0.5  # 用海龍公式求三角形面積
            area = (s * (s-a) * (s-b) * (s-c))**0.5
            if area > imax: imax = area  # 更新最大值
        result.append(f"{imax:.2f}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月18日 星期一

ZeroJudge 解題筆記:d261. 11000 - Bee

作者:王一哲
日期:2026年5月18日


ZeroJudge 題目連結:d261. 11000 - Bee

解題想法


只有第一隻母蜂不會死,剩下的公蜂、母蜂每年結束都會死去。第 $i$ 年的母蜂數量等於 $1$ 加上第 $i-1$ 年的公蜂數量,第 $i$ 年的公蜂數量等於第 $i-1$ 年的公蜂加母蜂數量。

Python 程式碼


使用時間約為 15 ms,記憶體約為 8.4 MB,通過測試。
def solve():
    import sys

    maxn = 50
    f = [0]*(maxn + 1)
    m = [0]*(maxn + 1)
    f[0] = 1
    for i in range(1, maxn + 1):
        f[i] = 1 + m[i-1]
        m[i] = f[i-1] + m[i-1]

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])
        ptr += 1
        if n == -1: break
        result.append(f"{m[n]:d} {f[n]+m[n]:d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月17日 星期日

ZeroJudge 解題筆記:d260. 11455 - Behold my quadrangle

作者:王一哲
日期:2026年5月17日


ZeroJudge 題目連結:d260. 11455 - Behold my quadrangle

解題想法


先將 4 個邊排序後分別存入 $a, b, c, d$,如果 $a, b, c, d$ 皆相等,輸出 square;如果 $a$ 等於 $b$ 且 $c$ 等於 $d$,輸出 rectangle;如果 $a + b + c > d$,輸出 quadrangle;其它狀況輸出 banana。

Python 程式碼


使用時間約為 22 ms,記憶體約為 8.4 MB,通過測試。
T = int(input())
for _ in range(T):
    a, b, c, d = sorted(map(int, input().split()))
    if a == b == c == d:
        print("square")
    elif a == b and c == d:
        print("rectangle")
    elif a + b + c > d:
        print("quadrangle")
    else:
        print("banana")

如果是多筆測資可以改成這樣,使用時間約為 15 ms,記憶體約為 8.2 MB,通過測試。
def solve():
    import sys

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        T = int(data[ptr])
        ptr += 1
        for _ in range(T):
            a, b, c, d = sorted(map(int, data[ptr:ptr+4]))
            ptr += 4
            if a == b == c == d:
                result.append("square\n")
            elif a == b and c == d:
                result.append("rectangle\n")
            elif a + b + c > d:
                result.append("quadrangle\n")
            else:
                result.append("banana\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月16日 星期六

ZeroJudge 解題筆記:d258. 11313 - Gourmet Games

作者:王一哲
日期:2026年5月16日


ZeroJudge 題目連結:d258. 11313 - Gourmet Games

解題想法


用一個 while 迴圈,當 $n \geq m$ 時繼續執行,每次執行時將集數 $cnt$ 加上 n//m,$n$ 改為 n = n//m + n%m。由於最後只能有一個優勝者,$n$ 最後必須等於 1,如果 $n$ 等於 1 輸出 $cnt$,反之輸出 cannot do this。

Python 程式碼


使用時間約為 29 ms,記憶體約為 8.2 MB,通過測試。
t = int(input())
for _ in range(t):
    n, m = map(int, input().split())
    cnt = 0
    while n >= m:
        cnt += n//m
        n = n//m + n%m
    print(cnt if n == 1 else "cannot do this")

使用時間約為 30 ms,記憶體約為 10.6 MB,通過測試。
def solve():
    import sys

    result = []
    data = sys.stdin.read().split() 
    t = int(data[0])
    ptr = 1
    for _ in range(t):  # 只能跑 t 次,否則會吃 OLE
        n = int(data[ptr])
        m = int(data[ptr+1])
        ptr += 2
        cnt = 0
        while n >= m:
            cnt += n//m
            n = n//m + n%m
        if n == 1: result.append(f"{cnt:d}\n")
        else: result.append("cannot do this\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月15日 星期五

ZeroJudge 解題筆記:d256. 11388 - GCD LCM

作者:王一哲
日期:2026年5月15日


ZeroJudge 題目連結:d256. 11388 - GCD LCM

解題想法


假設兩個數字 $a, b$ 的最大公因數 $G = GCD(a, b)$,最小公倍數 $L = LCM(a, b)$,而且題目要求「如果有多組解,輸出 $a$ 最小的一組」,答案就是 $a = G$,$b = L$,因為 $a$ 之中不能有 $G$ 以外大於 $1$ 的因數。如果 $L$ 不能被 $G$ 整除,則輸出 $-1$。

Python 程式碼


使用時間約為 15 ms,記憶體約為 8.8 MB,通過測試。
T = int(input())
for _ in range(T):
    G, L = map(int, input().split())
    if L%G != 0: print("-1")
    else: print(G, L)


C++ 程式碼


使用時間約為 1 ms,記憶體約為 1.5 MB,通過測試。
#include <cstdio>

int main() {
    int T; scanf("%d", &T);
    for(int t=0; t<T; t++) {
        int G, L; scanf("%d %d", &G, &L);
        if (L%G != 0) puts("-1");
        else printf("%d %d\n", G, L);
    }
    return 0;
}