Harryxun/sft_time huggingface dataset:
### BUGGY CODE ###

from sys import stdin
import math
import fractions
from collections import deque

INF = 10 ** 10

R, G, B, N = [int(x) for x in stdin.readline().rstrip().split()]

cnt = 0
RN = N // R + 1


for i in range(RN):
    GN = (N-R*i) // G + 1
    for j in range(GN):
        BN = (N-R*i-G*j) // B + 1
        for k in range(BN):
            num = R * i + G * j + B * k
            if num == N:
                cnt+=1

print(cnt)

### FIXED CODE ###

from sys import stdin
import math
import fractions
from collections import deque

INF = 10 ** 10

R, G, B, N = [int(x) for x in stdin.readline().rstrip().split()]

cnt = 0
R, G, B = sorted([R, G, B])
RN = N // R + 1
GN = N // G + 1
BN = N // B + 1

cnt = 0
for i in range(RN):
    tmpN = N - R*i
    if tmpN % G == 0:
        cnt += 1
    for j in range(GN):
        tmpN2 = tmpN - G*j
        if tmpN2 > 0 and tmpN2 % B == 0:
            cnt += 1
    

print(cnt)
### BUGGY CODE ###

import bisect

N = int(input())
S = []
for n in range(N):
    string = ''.join(sorted(input()))
    S.append(string)

S.sort()
ans = 0

for n in range(N - 1):
    tmp = n
    while S[tmp + 1] == S[tmp]:
        ans += 1
        if tmp == N - 2:
            break
        tmp += 1

print(ans)
#print(S)

### FIXED CODE ###

import bisect
import heapq
from collections import Counter

N = int(input())
S = []
for n in range(N):
    string = ''.join(sorted(input()))
    S.append(string)
ans = 0
counter_s = Counter(S)
for key, value in counter_s.items():
    if value >= 2:
        ans += value * (value - 1) // 2
print(ans)
### BUGGY CODE ###

def rec(n):
    m = str(n)
    c = m[0]
    get = n
    for i in range(len(m)):
        if m[i] != c:
            get = rec(n+1)

    return get



n = int(input())
res = rec(n)

print(res)


### FIXED CODE ###

a=input()
if(a[0]>=a[1] and a[0]>=a[2]):
    print(str(a[0])+str(a[0])+str(a[0]))
else :
    print (str(int(a[0])+1)+str(int(a[0])+1)+str(int(a[0])+1))
### BUGGY CODE ###

import sys
from collections import OrderedDict
input = sys.stdin.buffer.readline
sys.setrecursionlimit(10**6)


class Graph():
    def __init__(self):
        self.adjacency_dict = {}
        self.counter_dict = OrderedDict()

    def add_vertex(self, v):
        self.adjacency_dict[v] = []
        self.counter_dict[v] = 0

    def add_edge(self, v1, v2):
        self.adjacency_dict[v1].append(v2)
        self.adjacency_dict[v2].append(v1)

    def add_count(self, v, count):
        self.counter_dict[v] += count

    def dfs(self, v, pv):
        for nv in self.adjacency_dict[v]:
            if nv != pv:
                self.counter_dict[nv] += self.counter_dict[v]
                self.dfs(nv, v)

    def print_counters(self):
        print(*self.counter_dict.values())


def main():
    n, q = map(int, input().split())
    tree = Graph()
    for v in range(1, n+1):
        tree.add_vertex(v)
    for _ in range(n-1):
        a, b = map(int, input().split())
        tree.add_edge(a, b)
    for _ in range(q):
        p, x = map(int, input().split())
        tree.add_count(p, x)
    tree.dfs(1, 0)
    tree.print_counters()


if __name__ == "__main__":
    main()


### FIXED CODE ###

import sys
from collections import OrderedDict

input = sys.stdin.buffer.readline
sys.setrecursionlimit(10**6)


class Graph():
    def __init__(self):
        self.adjacency_dict = {}
        self.counter_dict = OrderedDict()

    def add_vertex(self, v):
        self.adjacency_dict[v] = set()
        self.counter_dict[v] = 0

    def add_edge(self, v1, v2):
        self.adjacency_dict[v1].add(v2)
        self.adjacency_dict[v2].add(v1)

    def add_count(self, v, count):
        self.counter_dict[v] += count

    def dfs_stack(self, start):
        stack = [start]
        visited = set()

        parent_vertex = 0
        while stack:
            current_vertex = stack.pop()
            visited.add(current_vertex)
            for v in self.adjacency_dict[current_vertex]:
                if v not in visited and v != parent_vertex:
                    self.counter_dict[v] += self.counter_dict[current_vertex]
                    stack.append(v)
            parent_vertex = current_vertex

    def dfs_rec(self, v, pv):
        for nv in self.adjacency_dict[v]:
            if nv != pv:
                self.counter_dict[nv] += self.counter_dict[v]
                self.dfs_rec(nv, v)

    def print_counters(self):
        print(*self.counter_dict.values())


def main():
    n, q = map(int, input().split())
    tree = Graph()
    for v in range(1, n+1):
        tree.add_vertex(v)
    for _ in range(n-1):
        a, b = map(int, input().split())
        tree.add_edge(a, b)
    for _ in range(q):
        p, x = map(int, input().split())
        tree.add_count(p, x)
    tree.dfs_stack(1)
    # tree.dfs_rec(1, 0)
    tree.print_counters()


if __name__ == "__main__":
    main()
### BUGGY CODE ###

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from sys import stdin

N, M = [int(x) for x in stdin.readline().rstrip().split()]

clear_list = [1] * N
    
for i in range(M):
    start, end  = [int(x) for x in stdin.readline().rstrip().split()]
    for i in range(1,N+1):
        if i < start or end < i:
            clear_list[i-1] = 0

print(clear_list.count(1))


### FIXED CODE ###

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from sys import stdin

N, M = [int(x) for x in stdin.readline().rstrip().split()]

clear_list = [1] * N
start = 0
end = 0
ans_start = 0
ans_end = 0
    
for i in range(M):
    start, end  = [int(x) for x in stdin.readline().rstrip().split()]
    if ans_start == 0 or ans_start < start : 
        ans_start = start
    if ans_end == 0 or ans_end > end:
        ans_end = end

if ans_end - ans_start < 0:
    print(0)
else:
    print(ans_end - ans_start + 1 )
### BUGGY CODE ###

import sys
input = sys.stdin.readline


def main():
    N = int(input())
    # dp[i][j][k] := 寿司が 1 つある皿が i 皿、2 つが j 皿、
    # 3 つが k 皿の状態から全て食べ終えるまでの操作回数の期待値
    dp = [[[0.0] * (N+1) for _ in range(N+1)] for _ in range(N+1)]

    a = list(map(int, input().split()))
    I, J, K = a.count(1), a.count(2), a.count(3)

    # 小さい方から dp を埋める
    for k in range(N+1):
        for j in range(N+1):
            for i in range(N+1):
                s = i + j + k
                if s != 0 and s <= N:
                    # 式変形はググった…
                    dp[i][j][k] = N
                    if i > 0:
                        dp[i][j][k] += dp[i-1][j][k] * i
                    if j > 0:
                        dp[i][j][k] += dp[i+1][j-1][k] * j
                    if k > 0:
                        dp[i][j][k] += dp[i][j+1][k-1] * k
                    dp[i][j][k] /= s

    print(dp[I][J][K])


if __name__ == '__main__':
    main()


### FIXED CODE ###

import sys
input = sys.stdin.readline

N = int(input())
# dp[i][j][k] := 寿司が 1 つある皿が i 皿、2 つが j 皿、
# 3 つが k 皿の状態から全て食べ終えるまでの操作回数の期待値
dp = [[[float(0)] * (N+1) for _ in range(N+1)] for _ in range(N+1)]

a = list(map(int, input().split()))
I, J, K = a.count(1), a.count(2), a.count(3)

# 小さい方から dp を埋める
for k in range(N+1):
    for j in range(N+1):
        for i in range(N+1):
            if (i+j+k) <= N:
                # 式変形はググった…
                if (i+j+k) != 0:
                    dp[i][j][k] = float(N) / float(i+j+k)
                if i > 0:
                    dp[i][j][k] += dp[i-1][j][k] * float(i) / float(i+j+k)
                if j > 0:
                    dp[i][j][k] += dp[i+1][j-1][k] * float(j) / float(i+j+k)
                if k > 0:
                    dp[i][j][k] += dp[i][j+1][k-1] * float(k) / float(i+j+k)
print(dp[I][J][K])
### BUGGY CODE ###

N, K = map(int, input().split())
p = tuple(map(int, input().split()))

max = 0
ite = N - K + 1
max = 0
base = sum(p[0:K])
for i in range(ite):
    S = 0
    for j in range(i, i+K):
        S += p[j]
    if S > max:
        max = S
        index = i

E = [None]*K
for i in range(K):
    E[i] = sum(range(1, p[index+i]+1))/p[index+i]
print(sum(E))

### FIXED CODE ###

import sys

N, K = map(int, sys.stdin.readline().split())
p = tuple(map(int, sys.stdin.readline().split()))

max = 0
ite = N - K
base = sum(p[0:K])
max = base
index = 0
for i in range(ite):
    tmp = base + p[i+K] - p[i]
    if tmp > max:
        max = tmp
        index = i+1
    base = tmp

E = [(1+p[index+i])/2 for i in range(K)]
print(sum(E))
### BUGGY CODE ###

n, a = map(int, input().split())
X = list(map(int, input().split()))

# editorial 参照 -> 3 dimentional DP
# 制約1: x1-xjのカード, 制約2: k枚選択, 制約3: 点数合計A*k
sum_X = sum(X)
DP = [[[0 for _ in range(sum_X+1)] for _ in range(n+1)] for _ in range(n+1)]


for j in range(n+1):
    for k in range(n+1):
        for s in range(sum_X+1):
            if (j==0) and (k==0) and (s==0):
                DP[j][k][s] = 1
            elif (j >= 1) and (s < X[j-1]):
                DP[j][k][s] = DP[j-1][k][s]
            elif (j >= 1) and (k >= 1) and (s >= X[j-1]):
                DP[j][k][s] = DP[j-1][k][s] + DP[j-1][k-1][s-X[j-1]]
            else:
                DP[j][k][s] = 0

ans  = 0
for k in range(1, n+1):
    if a*k > sum_X:
        pass
    else:
        ans += DP[n][k][a*k]

print(ans)

### FIXED CODE ###

n, a = map(int, input().split())
X = list(map(int, input().split()))

# editorial 参照 -> 3 dimentional DP
# 制約1: x1-xjのカード, 制約2: k枚選択, 制約3: 点数合計A*k
sum_X = sum(X)
DP = [[[0 for _ in range(sum_X+1)] for _ in range(n+1)] for _ in range(n+1)]


for j in range(n+1):
    for k in range(n+1):
        for s in range(sum_X+1):
            if (j==0) and (k==0) and (s==0):
                DP[j][k][s] = 1
            elif (j >= 1) and (s < X[j-1]):
                DP[j][k][s] = DP[j-1][k][s]
            elif (j >= 1) and (k >= 1) and (s >= X[j-1]):
                DP[j][k][s] = DP[j-1][k][s] + DP[j-1][k-1][s-X[j-1]]
            else:
                DP[j][k][s] = 0

ans  = 0
for k in range(1, n+1):
    if a*k > sum_X:
        pass
    else:
        ans += DP[n][k][a*k]

print(ans)
### BUGGY CODE ###

#!/usr/bin/env python3
N = int(input())

s = []
print(0)
s.append(input())
if s[-1] == 'Vacant':
    exit()

l, r = 0, N
while r - l > 2:
    m = (l + r) // 2
    print(m)
    s.append(input())
    if s[-1] != 'Vacant':
        exit()

    if s[i - 1] == s[i]:
        l, r = (l, m) if (m - l) % 2 == 1 else (m, r)
    else:
        l, r = (m, r) if (m - l) % 2 == 1 else (l, m)
print(m + 1)


### FIXED CODE ###

#!/usr/bin/env python3
N = int(input())

print(0, flush=True)
w0 = input()
if w0 == 'Vacant':
    exit()

l, r = 0, N
while True:
    m = (l + r) // 2
    print(m, flush=True)
    w1 = input()
    if w1 == 'Vacant':
        break
    if m % 2 == (w0 != w1):
        l = m
    else:
        r = m
### BUGGY CODE ###

from collections import deque
N = int(input())
A = list(deque(map(int, input().split())) for _ in range(N))
for i in range(N):
    for j in range(N - 1):
        A[i][j] -= 1

ans = 0
change = True
while change:
    change = False
    work = [-1] * N
    for i in range(N):
        if not A[i]:
            continue
        enemy = A[i][0]
        work[i] = enemy
        if work[work[i]] == i:
            A[i].popleft()
            A[enemy].popleft()
            change = True
    if not change:
        break
    ans += 1


empty = True
for row in A:
    if row:
        empty = False
if not empty:
    print('-1')
else:
    print(ans)



### FIXED CODE ###

from collections import deque
from pprint import pprint
N = int(input())
nextGame = [deque()] + [deque(map(int , input().split())) for _ in range(N)]
#print(nextGame)

canPlay = [[False] * (N + 1) for _ in range(N + 1)]
#pprint(canPlay)
days = [0] * (N + 1)
que = ([i for i in range(N + 1)])

while que:
    now = que.pop()
    #print("------------------------")
    if not nextGame[now]:
        continue
    enemy = nextGame[now].popleft()
    canPlay[now][enemy] = True
    #print("now : ",now)
    #print("enemy : ",enemy)
    #pprint(canPlay)

    if canPlay[now][enemy] and canPlay[enemy][now]:
        days[now] = days[enemy] = max(days[now], days[enemy]) + 1
        que.append(now)
        que.append(enemy)
    #print("days : ",days)

for test in nextGame:
    if test:
        print("-1")
        exit(0)
print(max(days))
### BUGGY CODE ###

N,Q=map(int,input().split())
S=input()
k=[S[0:2]]
for i in range(2,N):
  k.append(k[-1][-1]+S[i])
k.append(S[-1])

for _ in range(Q):
  f,l = map(int,input().split())
  print(k[f-1:l-1].count('AC'))

### FIXED CODE ###

N,Q=map(int,input().split())
S=input()
k = [0] * (N+1)

for i in range(1,N):
  v = 1 if S[i-1]+S[i] == 'AC' else 0
  k[i] = k[i-1] + v
k[-1]=k[-2]
for _ in range(Q):
  f,l = map(int,input().split())
  print(k[l-1] - k[f-1])
### BUGGY CODE ###

h,w=map(int,input().split())
field=[list(input()) for i in range(h)]
queue=[]
for i in range(h):
  for j in range(w):
    if field[i][j]=='#':
      queue.append([i,j])
p=[[0,1],[0,-1],[1,0],[-1,0]]
ans=0
while len(queue)>0:
  ans+=1
  manu=queue.copy()
  queue.clear()
  save=True
  for now in manu:
    for i in range(4):
      x=now[0]+p[i][0]
      y=now[1]+p[i][1]
      if x>-1 and x<h and y>-1 and y<w and field[x][y]=='.':
        field[x][y]='#'
        queue.append([x,y])
        save=False
  if save:
    ans-=1
print(ans)

### FIXED CODE ###

import numpy as np
h,w=map(int,input().split())
field=[list(input()) for i in range(h)]
field=[[0 if field[j][i]=='#' else h+w for i in range(w)]for j in range(h)]
field=np.array(field)
for i in range(1,h):
  field[i,:]=np.minimum(field[i,:],field[i-1,:]+1)
for i in range(h-1,0,-1):
  field[i-1,:]=np.minimum(field[i,:]+1,field[i-1,:])
for i in range(1,w):
  field[:,i]=np.minimum(field[:,i],field[:,i-1]+1)
for i in range(w-1,0,-1):
  field[:,i-1]=np.minimum(field[:,i]+1,field[:,i-1])
print(np.max(field))
### BUGGY CODE ###

import itertools
import math
import string
import collections
from collections import Counter
from collections import deque
import sys
sys.setrecursionlimit(2*10**5)
INF = 2**60


def readints():
    return list(map(int, input().split()))


def nCr(n, r):
    return math.factorial(n)//(math.factorial(n-r)*math.factorial(r))


def has_duplicates2(seq):
    seen = []
    for item in seq:
        if not(item in seen):
            seen.append(item)
    return len(seq) != len(seen)


def divisor(n):
    divisor = []
    for i in range(1, n+1):
        if n % i == 0:
            divisor.append(i)
    return divisor


# coordinates
dx = [-1, -1, -1, 0, 0, 1, 1, 1]
dy = [-1, 0, 1, -1, 1, -1, 0, 1]


N, M = map(int, input().split())
a = []
memo = [0]*(N+1)
for _ in range(M):
    a.append(int(input()))

safe = [True]*(N+1)
for i in range(M):
    safe[(a[i])] = False


def func(i):
    global safe

    if not(safe[i]):
        return 0
    if memo[i] != 0:
        return memo[i]
    if i == 0:
        return 1
    if i == 1:
        return 1
    ret = 0
    if i >= 2:
        ret += func(i-1)+func(i-2)
        memo[i] = ret
        return ret


print(func(N) % 1000000007)


### FIXED CODE ###

import math
import string
import collections
from collections import Counter
from collections import deque


def readints():
    return list(map(int, input().split()))


def nCr(n, r):
    return math.factorial(n)//(math.factorial(n-r)*math.factorial(r))


def has_duplicates2(seq):
    seen = []
    for item in seq:
        if not(item in seen):
            seen.append(item)
    return len(seq) != len(seen)


def divisor(n):
    divisor = []
    for i in range(1, n+1):
        if n % i == 0:
            divisor.append(i)
    return divisor


# coordinates
dx = [-1, -1, -1, 0, 0, 1, 1, 1]
dy = [-1, 0, 1, -1, 1, -1, 0, 1]

N, M = map(int, input().split())
a = []
for _ in range(M):
    a.append(int(input()))
# print(a)
dp = [0]*(N+1)
#dp[0] = 1
#dp[1] = 1
# for i in range(2, N):
#    dp[i] = dp[i-1]+dp[i-2]
safe = [True]*(N+1)
for i in range(M):
    safe[(a[i])] = False
#print('safe', safe)
dp[0] = 1
if safe[1]:
    dp[1] = 1
for i in range(2, N+1):
    if safe[i]:
        dp[i] = dp[i-1]+dp[i-2]
    if not(safe[i]):
        dp[i] = 0
#print('dp', dp)
print(dp[N] % 1000000007)
### BUGGY CODE ###

#!/usr/bin/env python3

import sys
import math
from bisect import bisect_right as br
from bisect import bisect_left as bl
sys.setrecursionlimit(2147483647)
from heapq import heappush, heappop,heappushpop
from collections import defaultdict
from itertools import accumulate
from collections import Counter
from collections import deque
from operator import itemgetter
from itertools import permutations
mod = 10**9 + 7
inf = float('inf')
def I(): return int(sys.stdin.readline())
def LI(): return list(map(int,sys.stdin.readline().split()))

n = I()
c = LI()
c.sort(reverse=True)
dp = [0]*n
dp[0] = c[0]
p = 1
for i in range(n-1):
    dp[i+1] = (2*dp[i] + p*(2+i+1)*c[i+1]) % mod
    p *= 2
print(dp[-1]*(2*p) % mod)

### FIXED CODE ###

#!/usr/bin/env python3

import sys
import math
from bisect import bisect_right as br
from bisect import bisect_left as bl
sys.setrecursionlimit(2147483647)
from heapq import heappush, heappop,heappushpop
from collections import defaultdict
from itertools import accumulate
from collections import Counter
from collections import deque
from operator import itemgetter
from itertools import permutations
mod = 10**9 + 7
inf = float('inf')
def I(): return int(sys.stdin.readline())
def LI(): return list(map(int,sys.stdin.readline().split()))

"""
S,T
"""

n = I()
c = LI()
c.sort(reverse=True)
dp = [0]*n
dp[0] = c[0]
p = 1
for i in range(n-1):
    dp[i+1] = (2*dp[i] + p*(2+i+1)*c[i+1]) % mod
    p *= 2
    p %= mod
p *= 2
p %= mod
print(dp[-1]*p % mod)
### BUGGY CODE ###

def isPrime(p):
	if p == 2: return 1
	if p < 2 or p&1 == 0: return 0
	return 1 if pow(2,p-1,p) == 1 else 0

while True:
	try:
		n = int(raw_input())
		print sum(isPrime(i) for i in range(3,n+1,2))+1
	except:
		break

### FIXED CODE ###

import math
n = []
while True:
    try:
        n.append(int(raw_input()))
    except:
        break
  
r = max(n)+1
sqrt = int(math.sqrt(r))
p = [1]*r
p[0] = 0
p[3::2] = [0 for x in range(3,r,2)]
for i in range(2,sqrt,2):
    if p[i]:
        p[2*i+1::i+1] = [0 for x in range(2*i+1,r,i+1)] 
  
for i in n:
     print sum(p[:i])
### BUGGY CODE ###

n= int(input())
a = list(map(int,input().split()))
score=1
for i in a:
  score*=i
if score>1e18:
  score=-1
print(score)


### FIXED CODE ###

n= int(input())
a = list(map(int,input().split()))
score=1
if 0 in a:
  print(0)
  exit()
for i in a:
  score*=i
  if score>10**18:
    print(-1)
    exit()
print(score)
### BUGGY CODE ###

s = input()
t = input()
s_len = len(s)
t_len = len(t)

# dp[i][j] = sのi文字目、tのj文字目までの最大長の部分文字列
dp = [['' for j in range(t_len + 1)] for i in range(s_len + 1)]
for si in range(1, s_len + 1):
    for ti in range(1, t_len + 1):
        dp_len = len(dp[si][ti])
        if s[si - 1] == t[ti - 1]:
            if dp_len < len(dp[si - 1][ti - 1] + s[si - 1]):
                dp[si][ti] = dp[si - 1][ti - 1] + s[si - 1]
                dp_len = len(dp[si][ti])
        if dp_len < len(dp[si - 1][ti]):
            dp[si][ti] = dp[si - 1][ti]
            dp_len = len(dp[si][ti])
        if dp_len < len(dp[si][ti - 1]):
            dp[si][ti] = dp[si][ti - 1]
print(dp[s_len][t_len])


### FIXED CODE ###

def dump(dp, i1_max, i2_max):
    for i1 in range(0, i1_max + 1):
        for i2 in range(0, i2_max + 1):
            print('%4d' % dp[i1][i2], end='')
        print()


s = input()
t = input()
s_len = len(s)
t_len = len(t)
inf = 1 << 60

# dp[i][j] = sのi文字目、tのj文字目までの最大長の部分文字列
dp = [[-inf for j in range(t_len + 1)] for i in range(s_len + 1)]
dp[0][0] = 0
for si in range(0, s_len + 1):
    for ti in range(0, t_len + 1):
        if si >= 1 and ti >= 1:
            if s[si - 1] == t[ti - 1]:
                dp[si][ti] = max(dp[si][ti], dp[si - 1][ti - 1] + 1)
        if si >= 1:
            dp[si][ti] = max(dp[si][ti], dp[si - 1][ti])
        if ti >= 1:
            dp[si][ti] = max(dp[si][ti], dp[si][ti - 1])

ans = ''
si = s_len
ti = t_len
#dump(dp, si, ti)
while si != 0 and ti != 0:
    if si >= 1 and ti >= 1:
        if (dp[si - 1][ti - 1] == dp[si][ti] - 1) and s[si - 1] == t[ti - 1]:
            ans = s[si - 1] + ans
            si -= 1
            ti -= 1
            continue
        if dp[si - 1][ti - 1] == dp[si][ti]:
            si -= 1
            ti -= 1
            continue
    if si >= 1:
        if dp[si - 1][ti] == dp[si][ti]:
            si -= 1
            continue
    if ti >= 1:
        if dp[si][ti - 1] == dp[si][ti]:
            ti -= 1
            continue

print(ans)
### BUGGY CODE ###


import numpy as np
from collections import deque

def parse():
  H, W = map(int, input().split(" "))
  grid = [list(input()) for y in range(H)]
  return H, W, grid

def print_grid(grid):
  H = len(grid)
  print("grid:")
  for line in grid:
    for c in line:
      print(c, end="")
    print("")

def main():
  H, W, grid = parse()
  # print(H, W)
  # print_grid(grid)

  visited = [[0 for x in range(W)] for y in range(H)]
  # visited = np.zeros((H, W), int)
  # for y in range(H):
  #   for x in range(W):
  #     if grid[y][x] == ".":
  #       visited[y][x] = H * W

  # for y in range(1, H):  # ↓
  #   visited[y][:] = np.minimum(visited[y][:], visited[y - 1][:] + 1)

  # for y in range(H - 2, -1, -1):
  #   visited[y, :] = np.minimum(visited[y, :], visited[y + 1][:] + 1)

  # for x in range(1, W):
  #   visited[:, x] = np.minimum(visited[:, x], visited[:, x - 1] + 1)

  # for x in range(W - 2, -1, -1):
  #   visited[:, x] = np.minimum(visited[:, x], visited[:, x + 1] + 1)

  dark_points = [(x, y) for x in range(W) for y in range(H) if grid[y][x] == "#"]
  # print(dark_points)
  # exit(0)

  q = deque(dark_points)
  ans = 0
  while len(q) > 0:
    ans += 1
    next_q = deque([])
    for x, y in q:
      if y - 1 >= 0 and not visited[y - 1][x]: # 上
        visited[y - 1][x] = ans
        next_q.append((x, y - 1))
      if y + 1 < H and not visited[y + 1][x]: # 下
        visited[y + 1][x] = ans
        next_q.append((x, y + 1))
      if x - 1 >= 0 and not visited[y][x - 1]: # 左
        visited[y][x - 1] = ans
        next_q.append((x - 1, y))
      if x + 1 < W and not visited[y][x + 1]: # 右
        visited[y][x + 1] = ans
        next_q.append((x + 1, y))
    q = next_q

  print(ans - 1)

if __name__ == "__main__":
  main()

### FIXED CODE ###


import numpy as np

def parse():
  H, W = map(int, input().split(" "))
  grid = [list(input()) for y in range(H)]
  return H, W, grid

def print_grid(grid):
  H = len(grid)
  print("grid:")
  for line in grid:
    for c in line:
      print(c, end="")
    print("")

def main():
  H, W, grid = parse()
  # print(H, W)
  # print_grid(grid)

  # visited = [[W * H if grid[y][x] == "." else 0 for x in range(W)] for y in range(H)]
  visited = np.zeros((H, W), int)
  for y in range(H):
    # visited.append([])
    for x in range(W):
      if grid[y][x] == ".":
        visited[y][x] = H * W

  for y in range(1, H):  # ↓
    # 要素ごとの処理
    # print(visited)
    visited[y][:] = np.minimum(visited[y][:], visited[y - 1][:] + 1)
    # print(visited)
    # input()
    # print(visited[y])
    # exit(0)

  for y in range(H - 2, -1, -1):
    visited[y, :] = np.minimum(visited[y, :], visited[y + 1][:] + 1)

  for x in range(1, W):
    visited[:, x] = np.minimum(visited[:, x], visited[:, x - 1] + 1)

  for x in range(W - 2, -1, -1):
    visited[:, x] = np.minimum(visited[:, x], visited[:, x + 1] + 1)

  # print(visited)
  # exit(0)

  # max_len = 0
  # for y in range(H):
  #   max_val = max(visited[y])
  #   max_len = max_len if max_len > max_val else max_val
  # print(max_len)
  print(np.max(visited))

if __name__ == "__main__":
  main()