GCD on a grid (Codeforces 1955G)
Tags: Math, number theory

Not long ago, Egor learned about the Euclidean algorithm for finding the greatest common divisor of two numbers. The greatest common divisor of two numbers $$$a$$$ and $$$b$$$ is the largest number that divides both $$$a$$$ and $$$b$$$ without leaving a remainder. With this knowledge, Egor can solve a problem that he once couldn't.Vasily has a grid with $$$n$$$ rows and $$$m$$$ columns, and the integer $$${a_i}_j$$$ is located at the intersection of the $$$i$$$-th row and the $$$j$$$-th column. Egor wants to go from the top left corner (at the intersection of the first row and the first column) to the bottom right corner (at the intersection of the last row and the last column) and find the greatest common divisor of all the numbers along the path. He is only allowed to move down and to the right. Egor has written down several paths and obtained different GCD values. He became interested in finding the maximum possible GCD.Unfortunately, Egor is tired of calculating GCDs, so he asks for your help in finding the maximum GCD of the integers along the path from the top left corner to the bottom right corner of the grid.

Input: The first line contains an integer $$$t$$$ ($$$1 \le t \le {10}^{4}$$$) — the number of test cases.The first line of each test case contains two integers $$$n$$$ and $$$m$$$ ($$$1 \le n, m \le 100$$$) — the number of rows and columns of the grid.Then, there are $$$n$$$ lines, where the $$$i$$$-th line contains $$$m$$$ integers $$$(1 \le a_{i,j} \le {10}^{6}$$$) — the integers written in the $$$i$$$-th row and the $$$j$$$-th column of the grid.It is guaranteed that the sum of $$$n \cdot m$$$ does not exceed $$$2 \cdot {10}^{5}$$$ over all test cases.

Output: For each test case, output the maximum possible GCD along the path from the top left cell to the bottom right cell in a separate line.


Sample Inputs:
3
2 3
30 20 30
15 25 40
3 3
12 4 9
3 12 2
8 3 12
2 4
2 4 6 8
1 3 6 9

Sample Outputs:
10
3
1

Solution (Python):
import sys
input = sys.stdin.readline
from math import gcd
for _ in range(int(input())):
    (n, m) = map(int, input().split())
    g = [list(map(int, input().split())) for _ in range(n)]
    a = gcd(g[0][0], g[-1][-1])
    ew = 0
    d = [1, a]
    for i in range(2, a):
        if i ** 2 > a:
            break
        if a % i == 0:
            d.append(i)
            d.append(a // i)
    d.sort(reverse=1)
    dp = [[0] * m for _ in range(n)]
    for x in d:
        dp[0][0] = x
        for i in range(n):
            for j in range(m):
                if g[i][j] % x == 0:
                    if i > 0 and dp[i - 1][j] == x or (j > 0 and dp[i][j - 1] == x):
                        dp[i][j] = x
        if dp[-1][-1] == x:
            print(x)
            break

Solution (Python):
def main():

    def get_divisors(x):
        divisors = []
        for d in range(1, x + 1):
            if d * d > x:
                break
            if x % d == 0:
                divisors.append(d)
                d2 = x // d
                if d2 != d:
                    divisors.append(d2)
        divisors.sort(reverse=True)
        return divisors

    def check(d):
        reachable = [0] * (n * m)
        reachable[0] = 1
        for i in range(n):
            for j in range(m):
                if grid[i * m + j] % d == 0:
                    if i - 1 >= 0 and reachable[(i - 1) * m + j] == 1:
                        reachable[i * m + j] = 1
                    if j - 1 >= 0 and reachable[i * m + j - 1] == 1:
                        reachable[i * m + j] = 1
        return reachable[(n - 1) * m + m - 1] == 1
    t = int(input())
    allans = []
    for _ in range(t):
        (n, m) = readIntArr()
        grid = [0] * (n * m)
        for i in range(n):
            arr = readIntArr()
            for j in range(m):
                grid[i * m + j] = arr[j]
        for d in get_divisors(grid[0]):
            if check(d):
                ans = d
                break
        allans.append(ans)
    multiLineArrayPrint(allans)
    return
import sys
input = sys.stdin.buffer.readline

def oneLineArrayPrint(arr):
    print(' '.join([str(x) for x in arr]))

def multiLineArrayPrint(arr):
    print('\n'.join([str(x) for x in arr]))

def multiLineArrayOfArraysPrint(arr):
    print('\n'.join([' '.join([str(x) for x in y]) for y in arr]))

def readIntArr():
    return [int(x) for x in input().split()]

def makeArr(defaultValFactory, dimensionArr):
    dv = defaultValFactory
    da = dimensionArr
    if len(da) == 1:
        return [dv() for _ in range(da[0])]
    else:
        return [makeArr(dv, da[1:]) for _ in range(da[0])]

def queryInteractive(a, b, c):
    print('? {} {} {}'.format(a, b, c))
    sys.stdout.flush()
    return int(input())

def answerInteractive(x1, x2):
    print('! {} {}'.format(x1, x2))
    sys.stdout.flush()
inf = float('inf')
from math import gcd, floor, ceil
import math
for _abc in range(1):
    main()

Solution (Python):
import sys
import random
from types import GeneratorType
import bisect
import io, os
from bisect import *
from collections import *
from contextlib import redirect_stdout
from itertools import *
from array import *
from functools import lru_cache, reduce
from heapq import *
from math import sqrt, gcd, inf
RI = lambda : map(int, sys.stdin.buffer.readline().split())
RS = lambda : map(bytes.decode, sys.stdin.buffer.readline().strip().split())
RILST = lambda : list(RI())
DEBUG = lambda *x: sys.stderr.write(f'{str(x)}\n')
DIRS = [(0, 1), (1, 0), (0, -1), (-1, 0)]
DIRS8 = [(0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1), (-1, 0), (-1, 1)]
RANDOM = random.randrange(2 ** 62)
MOD = 10 ** 9 + 7
PROBLEM = '\n'

def iii():
    num = 0
    neg = False
    while True:
        c = sys.stdin.read(1)
        if c == '-':
            neg = True
            continue
        elif c < '0' or c > '9':
            continue
        while True:
            num = 10 * num + ord(c) - ord('0')
            c = sys.stdin.read(1)
            if c < '0' or c > '9':
                break
        return -num if neg else num

def lower_bound(lo: int, hi: int, key):
    """"""
    lo -= 1
    hi += 1
    while lo + 1 < hi:
        mid = lo + hi >> 1
        if key(mid):
            hi = mid
        else:
            lo = mid
    return hi

def bootstrap(f, stack=[]):

    def wrappedfunc(*args, **kwargs):
        if stack:
            return f(*args, **kwargs)
        else:
            to = f(*args, **kwargs)
            while True:
                if type(to) is GeneratorType:
                    stack.append(to)
                    to = next(to)
                else:
                    stack.pop()
                    if not stack:
                        break
                    to = stack[-1].send(to)
            return to
    return wrappedfunc

def solve():
    (n, m) = RI()
    g = []
    for _ in range(n):
        g.append(RILST())
    ans = gcd(g[0][0], g[-1][-1])
    f = [[] for _ in range(m)]
    f1 = [[] for _ in range(m)]
    for (i, row) in enumerate(g):
        f1 = f
        f = [[] for _ in range(m)]
        if i == 0:
            f[0] = [ans]
        for (j, v) in enumerate(row):
            if i:
                for x in f1[j]:
                    f[j].append(gcd(x, v))
            if j:
                for x in f[j - 1]:
                    f[j].append(gcd(x, v))
            a = sorted(set(f[j]))
            f[j] = []
            for x in range(len(a)):
                for y in range(x + 1, len(a)):
                    if a[y] % a[x] == 0:
                        break
                else:
                    f[j].append(a[x])
    print(max(f[-1]))
if __name__ == '__main__':
    t = 1
    if t:
        (t,) = RI()
        for _ in range(t):
            solve()
    else:
        solve()