CodeEff/ECCO huggingface dataset:
# Original solution
from collections import deque
def isok(x):
    que=deque(sorted(z%x for z in a))
    res=0
    while que:
        l=que[0]
        if l==0:
            que.popleft()
            continue
        r=que[-1]
        if r==0:
            que.pop()
            continue
        d=min(l,x-r)
        que[0]-=d
        que[-1]=(que[-1]+d)%x
        res+=d
    return res
        
def factor(N):
    arr=[]
    for i in range(1,int(N**0.5)+1):
        if(N%i==0):
            arr.append(i)
            if(N//i!=i):
                arr.append(N//i)
    return arr

n,k=list(map(int,input().split()))
a=list(map(int,input().split()))
sum_=sum(a)

fac=sorted(factor(sum_),reverse=True)
ans=1
for x in fac:
    c=isok(x)
    if c<=k:
        ans=x
        break
print(ans)


# Optimized solution
def factor(N):
    arr=[]
    for i in range(1,int(N**0.5)+1):
        if(N%i==0):
            arr.append(i)
            if(N//i!=i):
                arr.append(N//i)
    return arr

n,k=list(map(int,input().split()))
a=list(map(int,input().split()))
sum_=sum(a)

fac=sorted(factor(sum_),reverse=True)
ans=1
for x in fac:
    li=sorted(z%x for z in a)
    res=0
    cum=[0]*(n+1)
    for i in range(n):
        cum[i+1]=cum[i]+li[i]
    for i in range(1,n):
        l,r=cum[i],x*(n-i)-(cum[n]-cum[i])
        if l==r and r<=k:
            ans=max(ans,x)
print(ans)
# Original solution
# 割り切る数は、Aの総和の約数である
# 自分自身を除く約数について大きい順にすべて試して、当てはまるものがあれば答え

# 8,20を7の倍数に近づけるとき、
# 8 -> mod 7が1であり、-1か+6で7の倍数になる
# 20 -> mod 7が6であり、-6か+1で7の倍数になる
# -1と+1をペアにすることが出来て、この操作回数1をK = 3から引くと2となり、これが偶数ならOK

import sys
readline = sys.stdin.readline

N,K = list(map(int,readline().split()))
A = list(map(int,readline().split()))

all = sum(A)
divisors = []
for i in range(1,int(all ** 0.5) + 1):
  if all % i == 0:
    divisors.append(i)
    divisors.append(all // i)

divisors = sorted(divisors,reverse = True)

#print(divisors)

for d in divisors:
  mods = [0] * (N)
  for i in range(len(A)):
    mods[i] = A[i] % d
  mods = sorted(mods)
  #print("d",d,"mods",mods)
  mods_front = [0] * N
  mods_front[0] = mods[0]
  for i in range(1,N):
    mods_front[i] = mods_front[i - 1] + mods[i]
  mods_back = [0] * N
  mods_back[-1] = d - mods[-1]
  #print("mods_front",mods_front)
  for i in range(N - 2,-1,-1):
    mods_back[i] = mods_back[i + 1] + (d - mods[i])
  #print("mods_back",mods_back)
  for i in range(N - 1):
    if mods_front[i] == mods_back[i + 1]:
      if K >= min(mods_front[i],mods_back[i + 1]):
        print(d)
        exit(0)
else:
  print((1))

# Optimized solution
# 割り切る数は、Aの総和の約数である
# 自分自身を除く約数について大きい順にすべて試して、当てはまるものがあれば答え

# 8,20を7の倍数に近づけるとき、
# 8 -> mod 7が1であり、-1か+6で7の倍数になる
# 20 -> mod 7が6であり、-6か+1で7の倍数になる

import sys
readline = sys.stdin.readline

N,K = list(map(int,readline().split()))
A = list(map(int,readline().split()))

all = sum(A)
divisors = []
for i in range(1,int(all ** 0.5) + 1):
  if all % i == 0:
    divisors.append(i)
    divisors.append(all // i)

divisors = sorted(divisors,reverse = True)

for d in divisors:
  mods = [0] * (N)
  for i in range(len(A)):
    mods[i] = A[i] % d
  mods = sorted(mods)
  mods_front = [0] * N
  mods_front[0] = mods[0]
  for i in range(1,N):
    mods_front[i] = mods_front[i - 1] + mods[i]
  mods_back = [0] * N
  mods_back[-1] = d - mods[-1]
  for i in range(N - 2,-1,-1):
    mods_back[i] = mods_back[i + 1] + (d - mods[i])
  for i in range(N - 1):
    if mods_front[i] == mods_back[i + 1]:
      if K >= mods_front[i]:
        print(d)
        exit(0)
else:
  print((1))
# Original solution
import sys

read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines
sys.setrecursionlimit(10 ** 9)
INF = 1 << 60
MOD = 1000000007


def divisors(n):
    lower = []
    upper = []
    for i in range(1, int(n ** 0.5) + 1):
        if n % i == 0:
            lower.append(i)
            if i != n // i:
                upper.append(n // i)

    lower.extend(reversed(upper))
    return lower


def main():
    N, K, *A = list(map(int, read().split()))

    total = sum(A)
    div = divisors(total)

    for d in reversed(div):
        vec = [a % d for a in A if a % d]
        if not vec:
            print(d)
            return
        vec.sort()
        M = len(vec)
        csum_sub = [0] * (M + 1)
        csum_add = [0] * (M + 1)
        for i in range(M):
            csum_sub[i + 1] = csum_sub[i] + vec[i]
            csum_add[i + 1] = csum_add[i] + d - vec[i]

        for i in range(1, M):
            if csum_sub[i] <= K and csum_sub[i] == csum_add[M] - csum_add[i]:
                print(d)
                return

    return


if __name__ == '__main__':
    main()


# Optimized solution
import sys

read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines
sys.setrecursionlimit(10 ** 9)
INF = 1 << 60
MOD = 1000000007


def divisors(n):
    lower = []
    upper = []
    for i in range(1, int(n ** 0.5) + 1):
        if n % i == 0:
            lower.append(i)
            if i != n // i:
                upper.append(n // i)

    lower.extend(reversed(upper))
    return lower


def main():
    N, K, *A = list(map(int, read().split()))

    total = sum(A)
    div = divisors(total)

    for d in reversed(div):
        vec = [a % d for a in A]
        vec.sort()

        M = len(vec)
        csum_sub = [0] * (M + 1)
        csum_add = [0] * (M + 1)
        for i in range(M):
            csum_sub[i + 1] = csum_sub[i] + vec[i]
            csum_add[i + 1] = csum_add[i] + d - vec[i]

        for i in range(M + 1):
            if csum_sub[i] <= K and csum_sub[i] == csum_add[M] - csum_add[i]:
                print(d)
                return

    return


if __name__ == '__main__':
    main()
# Original solution
N, K = list(map(int, input().split()))
A = list(map(int, input().split()))
Asum = sum(A)

div = set()
for i in range(1, int(Asum ** 0.5 + 0.5) + 1):
    if Asum % i == 0:
        div.add(i)
        div.add(Asum//i)

ans = 1
for d in div:
    now = 10 ** 18
    R = [a % d for a in A]
    R.sort()
    Rsum = sum(d - r for r in R)
    Lsum = 0
    for r in R:
        Lsum += r
        Rsum -= d - r
        now = min(now, max(Lsum, Rsum))

    if now <= K:
        ans = max(ans, d)

print(ans)


# Optimized solution
N, K = list(map(int, input().split()))
A = list(map(int, input().split()))
Asum = sum(A)

div = set()
for i in range(1, int(Asum ** 0.5 + 0.5) + 1):
    if Asum % i == 0:
        div.add(i)
        div.add(Asum//i)

ans = 1
for d in div:
    R = [a % d for a in A]
    R.sort()
    r = sum(R) // d
    l = N - r
    need = sum(R[:l])
    if need <= K:
        ans = max(ans, d)
print(ans)
# Original solution
inp = list([int(x) for x in input().split(" ")])
N = inp[0]
M = inp[1]

dp = [-1]*N

g = {}

def path(x):
    if dp[x-1]!=-1:
        return dp[x-1]
    if not x in list(g.keys()):
        return 0
    else:
        ret = 0
        for k in g[x]:
            if ret<path(k)+1:
                ret = path(k)+1
        dp[x-1] = ret
        return ret

for i in range(M):
    inp = list([int(x) for x in input().split(" ")])
    x = inp[0]
    y = inp[1]
    if not x in list(g.keys()):
        g[x] = []
    g[x].append(y)

ret = 0
for i in range(1,N+1):
    if ret<path(i):
        ret = path(i)

print(ret)

# Optimized solution
import sys
sys.setrecursionlimit(100000000)

inp = list([int(x) for x in input().split(" ")])
N = inp[0]
M = inp[1]

dp = [-1]*N

g = {}

def path(x):
    if dp[x-1]!=-1:
        return dp[x-1]
    if g[x] == []:
        return 0
    else:
        ret = 0
        for k in g[x]:
            if ret<path(k)+1:
                ret = path(k)+1
        dp[x-1] = ret
        return ret

for i in range(1,N+1):
    g[i] = []

for i in range(M):
    inp = list([int(x) for x in input().split(" ")])
    x = inp[0]
    y = inp[1]
    g[x].append(y)

ret = 0
for i in range(1,N+1):
    if ret<path(i):
        ret = path(i)

print(ret)
# Original solution
import sys

sys.setrecursionlimit(10 ** 5 * 2)
N, M = list(map(int, input().split()))
Ps = [[] for _ in range(N)]
for i in range(M):
    x, y = list(map(int, input().split()))
    Ps[x - 1].append(y - 1)

mem = [-1] * N


def rec(n):
    if mem[n] > -1:
        return mem[n]
    elif len(Ps[n]) == 0:
        mem[n] = 0
        return mem[n]
    else:
        mem[n] = max([rec(Ps[n][i]) for i in range(len(Ps[n]))]) + 1
        return mem[n]


for i in range(N):
    rec(i)
print((max(mem)))

# Optimized solution
import sys

sys.setrecursionlimit(10 ** 5 * 2)
input = sys.stdin.readline
N, M = list(map(int, input().split()))
Ps = [[] for _ in range(N)]
for i in range(M):
    x, y = list(map(int, input().split()))
    Ps[x - 1].append(y - 1)

mem = [-1] * N


def rec(n):
    if mem[n] > -1:
        return mem[n]
    elif len(Ps[n]) == 0:
        mem[n] = 0
        return mem[n]
    else:
        mem[n] = max([rec(Ps[n][i]) for i in range(len(Ps[n]))]) + 1
        return mem[n]


for i in range(N):
    rec(i)
print((max(mem)))
# Original solution
from collections import deque

def main():
  n, m = list(map(int, input().split()))
  tree_to = [[] for _ in range(n)]
  tree_from = [[] for _ in range(n)]
  for i in range(m):
    x, y = list(map(int, input().split()))
    tree_to[x-1].append(y-1)
    tree_from[y-1].append(x-1)
  
  ans = [0]*n
  already = [False]*n
  for i in range(n):
    if already[i]:
      continue
    already[i] = True
    not_yet = deque(tree_to[i])
    while not_yet:
      key = not_yet.pop()
      if ans[key] or not tree_to[key]:
        already[key] = True
        search = deque(tree_from[key])
        while search:
          already[i]
          sub = search.popleft()
          ans[sub] = 1
          for v in tree_to[sub]:
            if ans[sub] < ans[v]+1:
              ans[sub] = ans[v]+1
          for v in tree_from[sub]:
            search.append(v)
        continue
      for v in tree_to[key]:
        not_yet.append(v)
  print((max(ans)))
      

if __name__ == "__main__":
  main()

# Optimized solution
import sys
input = sys.stdin.readline
sys.setrecursionlimit(100007)

def main():
    n, m = list(map(int, input().split()))
    
    grid = [[] for _ in range(n)]
    
    for _ in range(m):
        x, y = list(map(int, input().split()))
        grid[x-1].append(y-1)
    
    memo = [-1]*n
    
    def dp(n):
        if memo[n] != -1:
            return memo[n]
        res = 0
        for v in grid[n]:
            res = max(res, dp(v)+1)
        memo[n] = res
        return res
    
    ans = 0
    for i in range(n):
        sub = dp(i)
        if ans < sub:
            ans = sub
        
    print(ans)
    
    
    
if __name__ == "__main__":
    main()
# Original solution
from collections import defaultdict
debug = print
def debug(*va): pass

N, M = map(int, input().split())
dummynode = N
N += 1

nextnodes = [defaultdict(list), defaultdict(list)]
for i in range(M):
    x, y = map(int, input().split())
    nextnodes[0][x - 1].append(y - 1)
    nextnodes[1][y - 1].append(x - 1)

# connect all nodes:
# dummynode -> all nodes
for i in range(N - 1):
    nextnodes[0][dummynode].append(i)
    nextnodes[1][i].append(dummynode)

def longest_by_topological_sort(i, nexts, prevs):
    visited = [-1] * N
    visited[i] = 0
    max_dist = 0
    que = []
    for n in nexts[i]:
        que.append(n)
    while que:
        p = que.pop(0)
        if visited[p] == -1:
            if all(visited[q] != -1 for q in prevs[p]):
                dist = max(visited[q] for q in prevs[p])
                visited[p] = dist + 1
                max_dist = max(max_dist, dist + 1)
                for n in nexts[p]:
                    que.append(n)
    return max(visited)

max_dist = longest_by_topological_sort(dummynode, nextnodes[0], nextnodes[1])
max_dist -= 1 # dummy

print(max_dist)


# Optimized solution
from collections import defaultdict
debug = print
def debug(*va): pass

def longest_by_topological_sort(N, nexts, prevs):
    visited = [-1] * N
    max_dist = 0
    que = list(range(N))
    while len(que):
        p = que.pop()
        if visited[p] == -1:
            if all(visited[q] != -1 for q in prevs[p]):
                dist = 0
                for q in prevs[p]:
                    dist = max(dist, visited[q] + 1)
                visited[p] = dist
                max_dist = max(max_dist, dist)
                for n in nexts[p]:
                    que.append(n)
    return max_dist

def test_separate():
    import time
    N = 10**5
    t0 = time.time()
    print(longest_by_topological_sort(N, defaultdict(list), defaultdict(list)))
    print('elapsed', time.time() - t0)

def test_fanout():
    import time
    N = 10**5
    nn, pp = defaultdict(list), defaultdict(list)
    for i in range(1, N):
        nn[0].append(i)
        pp[i].append(0)
    t0 = time.time()
    print(longest_by_topological_sort(N, nn, pp))
    print('elapsed', time.time() - t0)

def test_middle():
    import time
    N = 10**5
    nn, pp = defaultdict(list), defaultdict(list)
    for i in range(1, N):
        # fanout
        nn[0].append(i)
        pp[i].append(0)
        # fanin
        nn[i].append(1)
        pp[1].append(i)
    t0 = time.time()
    print(longest_by_topological_sort(N, nn, pp))
    print('elapsed', time.time() - t0)

if __name__ == '__main__':
    N, M = map(int, input().split())

    nextnodes = [defaultdict(list), defaultdict(list)]
    for i in range(M):
        x, y = map(int, input().split())
        nextnodes[0][x - 1].append(y - 1)
        nextnodes[1][y - 1].append(x - 1)

    max_dist = longest_by_topological_sort(N, nextnodes[0], nextnodes[1])
    print(max_dist)
# Original solution
from operator import itemgetter
# スペース区切りの整数入力
N,M = list(map(int, input().split()))
#指定数分の３つの整数を順番に受けてリストに入力
move = []
for i in range(M):
    move.append(list(map(int, input().split())))
move.sort(key=itemgetter(0))

dp = [-1] * (N+1)

def findpath(now_x):
    if dp[now_x] > -1:
        return dp[now_x]
    maxpath = 0
    for x,y in move:
        if now_x == x:
            maxpath = max(maxpath,findpath(y) + 1)
        if now_x < x:
            break
    dp[now_x] = maxpath
    return maxpath

Ans = 0
for do_x in range(1,N+1):
    Ans = max(Ans,findpath(do_x))

print(Ans)


# Optimized solution
import sys
sys.setrecursionlimit(10**5)

# スペース区切りの整数入力
N,M = list(map(int, input().split()))
#指定数分の３つの整数を順番に受けてリストに入力
move = {}
for i in range(M):
    x,y = list(map(int, input().split()))
    move.setdefault(x,[]).append(y)

dp = [-1] * (N+10)

def findpath(now_x):
    if dp[now_x] > -1:
        return dp[now_x]
    maxpath = 0
    if now_x in list(move.keys()):
        for y in move[now_x]:
            maxpath = max(maxpath,findpath(y) + 1)
    dp[now_x] = maxpath
    return maxpath

Ans = 0
for do_x in range(1,N+1):
    Ans = max(Ans,findpath(do_x))

print(Ans)
# Original solution
from collections import defaultdict
    
n, m = list(map(int, input().split()))
adj = defaultdict(list)
radj = defaultdict(list)

for i in range(m):
    s, e = list(map(int, input().split()))
    adj[s].append(e)
    radj[e].append(s)
    
mp = [0]*(n+1)
v = [0]*(n+1)
    
for i in range(1, 1+n):
    if len(adj[i]) == 0:
        q = [i]
        while q:
            e = q.pop()
            for j in radj[e]:
                mp[j] = max(mp[j], 1+mp[e])
                q.append(j)

print((max(mp)))

# Optimized solution
import sys
from collections import defaultdict
    
sys.setrecursionlimit(10**9)
    
n, m = list(map(int, input().split()))
adj = defaultdict(list)
radj = defaultdict(list)

for i in range(m):
    s, e = list(map(int, input().split()))
    adj[s].append(e)
    
dp = [-1]*(n+1)

def dfs(e):
    if dp[e] != -1:
        return dp[e]
    
    temp = 0
    for i in adj[e]:
        temp = max(temp, 1+dfs(i))
        
    dp[e] = temp
    return temp
    
    
for i in range(1, n+1):
    dfs(i)
    
print((max(dp)))
# Original solution
import sys
sys.setrecursionlimit(10**7)
N,M=list(map(int,input().split()))
table=[[] for i in range(N)]
Lin=[0]*N
for i in range(M):
    w,v=list(map(int,input().split()))
    table[w-1].append(v-1)
    Lin[v-1]+=1
H=[]
for i in range(N):
    if Lin[i]==0:
        H.append(i)
dp=[0]*N
def f(x):
    if len(table[x])==0:
        return
    for i in table[x]:
        if dp[i]<dp[x]+1:
            dp[i]=dp[x]+1
            f(i)
    return
for i in H:
    f(i)
print((max(dp)))

# Optimized solution
import sys
sys.setrecursionlimit(10**7)
N,M=list(map(int,input().split()))
table=[[] for i in range(N)]
Lin=[0]*N
for i in range(M):
    w,v=list(map(int,input().split()))
    table[w-1].append(v-1)
    Lin[v-1]+=1
H=[]
for i in range(N):
    if Lin[i]==0:
        H.append(i)
dp=[-1]*N
def f(x):
    if dp[x]!=-1:
        return dp[x]
    if len(table[x])==0:
        return 0
    t=0
    for i in table[x]:
        t=max(t,f(i)+1)
    dp[x]=t
    return t
for i in H:
    f(i)
print((max(dp)))
# Original solution
import sys
from collections import deque

input = sys.stdin.readline

N,M = list(map(int,input().split()))
edge = [list(map(int,input().split())) for _ in range(M)]

graph = [[] for _ in range(N)]
indegree = [0 for _ in range(N)]

for i in range(M):
    graph[edge[i][0]-1].append(edge[i][1]-1)
    indegree[edge[i][1]-1] += 1

queue = deque()
for i in range(N):
    if indegree[i] == 0:
        queue.append(i)

dp = [0]*N

while queue:
    node = queue.popleft()
    for adj in graph[node]:
        indegree[adj] -= 1
        if indegree[adj] == 0:
            queue.append(adj)
            dp[adj] = dp[node]+1

print((max(dp)))

# Optimized solution
import sys
input = sys.stdin.buffer.readline

N, M = list(map(int, input().split()))
graph = [[] for _ in range(N)]
deg = [0 for _ in range(N)]
dp = [0 for _ in range(N)]

for _ in range(M):
    x, y = list(map(int, input().split()))
    graph[x - 1].append(y - 1)
    deg[y - 1] += 1

stack = []

for i in range(N):
    if not deg[i]:
        stack.append(i)

while stack:
    node = stack.pop()
    for adj in graph[node]:
        deg[adj] -= 1
        dp[adj] = max(dp[adj], dp[node] + 1)
        if not deg[adj]:
            stack.append(adj)

print((max(dp)))
# Original solution
import sys
input = sys.stdin.readline


N, M = list(map(int, input().split()))
A = []
for _ in range(M):
    a = tuple(map(int, input().split()))
    A.append(a)
dp = [-1]*(N+1)


def dfs(n):
    global dp
    B = list([x for x in A if x[0] == n])
    if len(B) == 0:
        return 0
    ma = 0
    for b in B:
        x = dp[b[1]]
        if x != -1:
            ma = max(ma, x + 1)
        else:
            ma = max(ma, dfs(b[1]) + 1)
    dp[n] = ma
    return ma


def main():
    global dp
    for i in range(N):
        dp[i] = dfs(i+1)
    print((max(dp)))


if __name__ == '__main__':
    main()


# Optimized solution
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10000000)

N, M = list(map(int, input().split()))
G = [[] for _ in range(N)]
for _ in range(M):
    a, b = list(map(int, input().split()))
    G[a-1].append(b-1)
dp = [-1]*N


def dfs(n):
    global dp
    if dp[n] > 0:
        return dp[n]

    ma = 0
    for b in G[n]:
        ma = max(ma, dfs(b) + 1)
    dp[n] = ma
    return ma


def main():
    global dp
    for i in range(N):
        dp[i] = dfs(i)
    print((max(dp)))


if __name__ == '__main__':
    main()
# Original solution
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**5)

N, M = list(map(int, input().split()))
G = [[] for _ in range(N)]
for _ in range(M):
    a, b = list(map(int, input().split()))
    G[a-1].append(b-1)
dp = [-1]*N


def dfs(n):
    if dp[n] > 0:
        return dp[n]

    ma = 0
    for b in G[n]:
        ma = max(ma, dfs(b) + 1)
    return ma


def main():
    global dp
    for i in range(N):
        dp[i] = dfs(i)
    print((max(dp)))


if __name__ == '__main__':
    main()


# Optimized solution
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**5)

N, M = list(map(int, input().split()))
G = [[] for _ in range(N)]
for _ in range(M):
    a, b = list(map(int, input().split()))
    G[a-1].append(b-1)
dp = [-1]*N


def dfs(n):
    global dp
    if dp[n] > 0:
        return dp[n]

    ma = 0
    for b in G[n]:
        ma = max(ma, dfs(b) + 1)
    dp[n] = ma
    return ma


def main():
    global dp
    for i in range(N):
        dp[i] = dfs(i)
    print((max(dp)))


if __name__ == '__main__':
    main()
# Original solution
import sys, re, os
from collections import deque, defaultdict, Counter
from math import ceil, sqrt, hypot, factorial, pi, sin, cos, radians
from itertools import permutations, combinations, product, accumulate
from operator import itemgetter, mul
from copy import deepcopy
from string import ascii_lowercase, ascii_uppercase, digits
from heapq import heapify, heappop, heappush

def input(): return sys.stdin.readline().strip()
def INT(): return int(eval(input()))
def MAP(): return list(map(int, input().split()))
def S_MAP(): return list(map(str, input().split()))
def LIST(): return list(map(int, input().split()))
def S_LIST(): return list(map(str, input().split()))
 
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
mod = 10 ** 9 + 7

N, M = MAP()
L = [LIST() for i in range(M)]
graph = defaultdict(list)
for a, b in L:
    graph[a-1].append(b-1)
ans = 0
dist = [0] * N

for i in range(N):
    q = [i]
    while q:
        a = q.pop()
        for node in graph[a]:
            if dist[a] + 1 > dist[node]:
                dist[node] = dist[a] + 1
                # if ans < dist[node]:
                #     ans = dist[node]
                q.append(node)
if ans < max(dist):
    ans = max(dist)
print(ans)


# Optimized solution
import sys, re, os
from collections import deque, defaultdict, Counter
from math import ceil, sqrt, hypot, factorial, pi, sin, cos, radians
from itertools import permutations, combinations, product, accumulate
from operator import itemgetter, mul
from copy import deepcopy
from string import ascii_lowercase, ascii_uppercase, digits
from heapq import heapify, heappop, heappush

def input(): return sys.stdin.readline().strip()
def INT(): return int(eval(input()))
def MAP(): return list(map(int, input().split()))
def S_MAP(): return list(map(str, input().split()))
def LIST(): return list(map(int, input().split()))
def S_LIST(): return list(map(str, input().split()))
 
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
mod = 10 ** 9 + 7

N, M = MAP()
gout = [[] for i in range(N)]
deg = [0] * N

for i in range(M):
    x, y = MAP()
    gout[x-1].append(y-1)
    deg[y-1] += 1
# only no_children 
topo = [v for v in range(N) if deg[v] == 0]
path_len = [0] * N
ans = 0
q = deque(topo)
# 子を持たない子スタート
while q:
    v = q.popleft()
    for t in gout[v]:
        # 親の子，vのカウントを減らす
        deg[t] -= 1
        # それでそれ以外の子がいなくなったら，
        # トポロジカルソートではスタックに積む
        if deg[t] == 0:
            q.append(t)
            path_len[t] = path_len[v] + 1
            ans = path_len[t]
print(ans)
# Original solution
def main():
    import sys
    sys.setrecursionlimit(10**7)
    import collections
    dic=collections.defaultdict(list)

    N,M=list(map(int,sys.stdin.readline().split()))
    for i in range(M):
        x,y=list(map(int,sys.stdin.readline().split()))
        dic[x].append(y)


    dp=[0]*(N+1)
    def dfs(frm):
        if dp[frm]:
            return dp[frm]

        mx=0
        if frm not in list(dic.keys()):
            return 0

        for val in dic[frm]:
            mx=max(mx,dfs(val)+1)

        dp[frm]=mx
        return mx

    mx=0
    for key in list(dic.keys()):
        mx=max(mx,dfs(key))

    return mx

print((main()))


# Optimized solution
def main():
    import sys
    sys.setrecursionlimit(10**7)

    N,M=list(map(int,sys.stdin.readline().split()))
    dic=[[] for _ in range(N)]
    for i in range(M):
        x,y=list(map(int,sys.stdin.readline().split()))
        dic[x-1].append(y-1)


    dp=[0]*(N)
    def dfs(frm):
        if dp[frm]:
            return dp[frm]

        mx=0
        if not dic[frm]:
            return 0

        for val in dic[frm]:
            mx=max(mx,dfs(val)+1)

        dp[frm]=mx
        return mx

    mx=0
    for key in range(N):
        mx=max(mx,dfs(key))

    return mx

print((main()))