CodeEff/ECCO huggingface dataset:
# Original solution
import sys
input = sys.stdin.readline
from collections import defaultdict

S = input().strip()
l = len(S)
no_zero_dic = {}
dp = [[0 for _ in range(2019)] for i in range(l)]
ans = 0
for i in range(l):
    s = int(S[i])
    no_zero_dic[s] = 1
    _x = set(no_zero_dic.keys())
    for j in _x:
        k = (10 * j + s) % 2019
        dp[i][k] = dp[i-1][j]
        if dp[i-1][j] > 0:
            no_zero_dic[k] = 1
        if k == 0:
            ans += dp[i][k]
    dp[i][s] += 1


print(ans)


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

S = input().strip()
l = len(S)
dic = {0:[-1]}
dp = [[0 for _ in range(2019)] for i in range(l)]
ans = 0
mod = 0
for i in range(0, l):
    s = int(S[i:])
    mod = s % 2019
    if mod in dic:
        dic[mod].append(i)
    else:
        dic[mod] = [i]

for key, val in list(dic.items()):
    v_len = len(val)
    ans += (v_len * (v_len -1))// 2

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

S = input().strip()
l = len(S)
dic = {0:[-1]}
dp = [[0 for _ in range(2019)] for i in range(l)]
ans = 0
base = 1
mod = 0
for i in range(0, l):
    base = (10 * base) % 2019
    s = base * int(S[l-1-i]) + mod
    mod = s % 2019
    if mod in dic:
        dic[mod].append(i)
    else:
        dic[mod] = [i]

for key, val in list(dic.items()):
    v_len = len(val)
    ans += (v_len * (v_len -1))// 2

print(ans)



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

S = input().strip()
l = len(S)
dic = {0:[-1]}
ans = 0
base = 1
mod = 0
for i in range(0, l):
    base = (10 * base) % 2019
    s = base * int(S[l-1-i]) + mod
    mod = s % 2019
    if mod in dic:
        dic[mod].append(i)
    else:
        dic[mod] = [i]

for key, val in list(dic.items()):
    v_len = len(val)
    ans += (v_len * (v_len -1))// 2

print(ans)
# Original solution
s = str(eval(input()))
s=s[::-1]
mod = 2019
li = [0]*(len(s)+1)
cnt=1
for i in range(len(s)):
    li[i+1]=li[i] + int(s[i]) * cnt
    li[i+1]%=mod
    cnt*=10
import collections
A=collections.Counter(li[1:]);ans=0
for u,v in list(A.items()):
    ans+=v*(v-1)//2
    if u==0:
        ans+=v
print(ans)




# Optimized solution
s = str(eval(input()))
s=s[::-1]
mod = 2019
li = [0]*(len(s)+1)
cnt=1
for i in range(len(s)):
    li[i+1]=li[i] + int(s[i]) * cnt
    li[i+1]%=mod
    cnt*=10
    cnt%=mod
import collections
A=collections.Counter(li[1:]);ans=0
for u,v in list(A.items()):
    ans+=v*(v-1)//2
    if u==0:
        ans+=v
print(ans)
# Original solution
def main():
    import sys
    from collections import Counter
    S=sys.stdin.readline().strip()
    L=[0]*len(S)

    now=0
    for i in range(len(S)):
        now+=int(S[-i-1])*10**i
        L[-i-1]=now%2019

    dic=Counter(L)
    
    output=0
    for val in list(dic.values()):
        if val!=1:
            output+=val*(val-1)//2
    
    output+=dic[0]
    print(output)

main()


# Optimized solution
def pow_with_mod(x, n, m):
    if n == 0:
        return 1

    K = 1
    while n > 1:
        if n % 2 != 0:
            K *= x
            K %= m
        x *= x
        x %= m
        n //= 2

    return (K * x) % m

def main():
    import sys
    S=sys.stdin.readline().strip()
    N=len(S)
    L=[0]*2019
    now=0
    for i in range(N):
        now+=int(S[-i-1])*pow_with_mod(10, i, 2019)
        now%=2019
        L[now]+=1  
    print((L[0]+sum([x*(x-1)//2 for x in L])))
main()
# Original solution
#!/usr/bin/env python3
import sys


def solve(S: int):
    S =str(S)
    l = len(S)
    elds = [x*2019 for x in range(10000) if "0" not in str(x*2019)]
    # print(elds)
    s = S
    ans = []
    for t in range(5,9):
        for x in range(l-t+1):
            # print(s[x:x+t])           
            if int(s[x:x+t]) in elds:
                ans.append((x,x+t))

    p= [a_[0] for a_ in ans]
    q= [a_[1] for a_ in ans]
    
    print((len(ans)+len(set(p)&set(q))))
    

    return


# Generated by 1.1.6 https://github.com/kyuridenamida/atcoder-tools  (tips: You use the default template now. You can remove this line by using your custom template)
def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    S = int(next(tokens))  # type: int
    solve(S)

if __name__ == '__main__':
    main()


# Optimized solution
#!/usr/bin/env python3
import sys


def solve(S: int):
    S =str(S)[::-1]
    MOD = 2019
    mod_l = [int(0)]*2019
    mod_l[0] = 1
    prev = 0
    for x in range(len(S)):
        k = int(S[x]) * pow(10, x, MOD) % MOD + prev
        mod_l[k%2019] += 1
        prev = k%2019

    s = sum([x*(x-1)//2 for x in mod_l])
    print(s)
    return


# Generated by 1.1.6 https://github.com/kyuridenamida/atcoder-tools  (tips: You use the default template now. You can remove this line by using your custom template)
def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    S = int(next(tokens))  # type: int
    solve(S)

if __name__ == '__main__':
    main()
# Original solution
from collections import deque
#import time
#from sys import stdin

#start = time.time()#計測始
def main():
  s = str(eval(input()))
  ss = reversed(s)
  n=len(s)
  mlist=deque([0])
  slist=""
  for sss in ss:
    slist = sss + slist
    m = int(slist)%2019
    mlist.append(m)

  ll=len(mlist)
  l=len(set(mlist))

  print((ll-l))
  
main()

# Optimized solution
import time

s = input()[::-1] # 入力文字列を逆順でsに格納

counts = [0] * 2019
counts[0] = 1

num, d = 0, 1

for char in s:
    num += int(char) * d
    num %= 2019
    d *= 10
    d%= 2019
    counts[num] += 1

#start = time.time()#計測始
ans = 0
for cnt in counts:
    ans += cnt * (cnt - 1) // 2

print(ans) # 答えの出力
#end = time.time()#計測終
#print(f"{end-start}sec.")#計測出力
# Original solution
mul2019 = []
for i in range(2, 100):
    if str(i*2019).count("0")>0:
        continue
    mul2019.append(str(i*2019))
n = str(eval(input()))
cnt = 0
for j in range(4, len(n)):
    for i in range(len(n)-j+1):
        for r in mul2019:
            if str(r)==n[i:i+j]:
                cnt += 1 
print(cnt)

# Optimized solution
s = input()[::-1] # 入力文字列を逆順でsに格納

counts = [0] * 2019
counts[0] = 1
#余りの数字がそれぞれ何回出たかカウント
#count[0]は「累積和的」に0%2019を考えるために1にしている

num, d = 0, 1
#numは余りの累積和、dはcharの桁数
for char in s:
    num += int(char) * d
    num %= 2019
    d *= 10
    d%= 2019
    counts[num] += 1
'''
charに一桁ずつ取り出す。そのMOD2019を考え、累積和をとる
しかし、それぞれの数字には10の累乗がかかっているのでそれについては別途dを用意してMOD2019をとる
つまり、numは1桁目のMOD2019、2桁目のMOD2019に1桁目のMOD2019に加える
'''

ans = 0
for cnt in counts:
    ans += cnt * (cnt - 1) // 2

print(ans) # 答えの出力
# Original solution
def main():
    import sys
    import time
    from collections import defaultdict
    dic = defaultdict(int)

    input = sys.stdin.readline

    s = str(input().rstrip())
    m = 0

    for i in range(1,len(s)+1):
        m_ad = (int(s[-i]) * (10 ** (i - 1))) % 2019
        m = (m_ad + m) % 2019
        dic[m] += 1

    ans1 = 0

    for x in list(dic.values()):
        if x > 1:
            ans1 += x * (x - 1) // 2
    ans2 = dic[0]
    time.sleep(0.5)

    print((ans1 + ans2))

if __name__ == "__main__":
    main()

# Optimized solution
def main():
    import sys
    from collections import defaultdict
    dic = defaultdict(int)

    input = sys.stdin.readline

    s = str(input().rstrip())
    m = 0
    before_m = 0.1

    for i in range(1, len(s) + 1):
        before_m = int(before_m*10)%2019
        m_ad = (int(s[-i]) * before_m) % 2019
        m = (m_ad + m) % 2019
        dic[m] += 1

    ans1 = 0

    for x in list(dic.values()):
        if x > 1:
            ans1 += x * (x - 1) // 2
    ans2 = dic[0]

    print((ans1 + ans2))

if __name__ == "__main__":
    main()
# Original solution
from sys import stdin, setrecursionlimit
import collections


def initialize_cmb(m, mod=10 ** 9 + 7):
    fac = [0] * m
    finv = [0] * m
    inv = [0] * m
    fac[0] = 1
    finv[0] = 1
    if m > 1:
        fac[1] = 1
        finv[1] = 1
        inv[1] = 1
        for i in range(2, m):
            fac[i] = fac[i-1] * i % mod
            inv[i] = mod - inv[mod % i] * (mod // i) % mod
            finv[i] = finv[i - 1] * inv[i] % mod
    return fac, finv


def cmb(n, k, fac, finv, mod=10 ** 9 + 7):
    if n < k:
        return 0
    if n < 0 or k < 0:
        return 0
    return fac[n] * (finv[k] * finv[n - k] % mod) % mod


def main():
    input = stdin.readline
    s = list(input()[:-1])
    s = list(map(int, s))
    N = len(s)
    mod = [0] * N
    mod[-1] = s[-1] % 2019
    for i in reversed(list(range(N - 1))):
        mod[i] = (mod[i + 1] + s[i] * 10 ** (N - i - 1)) % 2019

    fac, finv = initialize_cmb(N)

    counter = collections.Counter(mod)

    ans = 0

    for k, v in list(counter.items()):
        if k == 0:
            ans += v
        elif v > 1:
            ans += cmb(v, 2, fac, finv)

    print(ans)


if __name__ == "__main__":
    setrecursionlimit(10000)
    main()


# Optimized solution
from sys import stdin, setrecursionlimit


def main():
    input = stdin.readline
    s = list(input()[:-1])[::-1]
    N = len(s)
    p10 = [1]
    tmp = 1
    for _ in range(N - 1):
        tmp = tmp * 10 % 2019
        p10.append(tmp)
    mod = []
    tmp = 0
    for num, p in zip(s, p10):
        tmp = (tmp + int(num) * p) % 2019
        mod.append(tmp)

    mod.sort()
    mod.insert(0, 0)

    ans = 0
    count = 1
    for i in range(1, N + 1):
        if mod[i] == mod[i - 1]:
            count += 1
        else:
            ans += count * (count - 1) // 2
            count = 1
    ans += count * (count - 1) // 2
    print(ans)


if __name__ == "__main__":
    setrecursionlimit(10000)
    main()
# Original solution
import math
from functools import reduce
from collections import deque,defaultdict
import sys
sys.setrecursionlimit(10**7)

# スペース区切りの入力を読み込んで数値リストにして返します。
def get_nums_l():
    return [ int(s) for s in input().split(" ")]

# 改行区切りの入力をn行読み込んで数値リストにして返します。
def get_nums_n(n):
    return [ int(input()) for _ in range(n)]

# 改行またはスペース区切りの入力をすべて読み込んでイテレータを返します。
def get_all_int():
    return map(int, open(0).read().split())

def log(*args):
    print("DEBUG:", *args, file=sys.stderr)

def hoge(n):
    count = 0
    i = 0
    while count < n:
        if "0" not in str(2019*i):
            count += 1
            print(2019*i)
        i += 1


s = input()
X = list(map(int, list(s)))
n = len(s)

ruiseki = [0] * (n+1)
for i in (range(n-1, -1, -1)):
    ruiseki[i] = (X[i] * 10**(n-i-1) + ruiseki[i+1]) % 2019

# log(ruiseki)

ans = 0
count = defaultdict(int)

for x in ruiseki:
    # log(count[x])
    ans += count[x]
    count[x] += 1
# log(count)
print(ans)


# Optimized solution
import math
from functools import reduce
from collections import deque,defaultdict
import sys
sys.setrecursionlimit(10**7)

def log(*args):
    print("DEBUG:", *args, file=sys.stderr)

s = input()
X = list(map(int, list(s)))
n = len(s)

ruiseki = [0] * (n+1)
for i in (range(n-1, -1, -1)):
    ruiseki[i] = (X[i] * pow(10, (n-i-1), 2019) + ruiseki[i+1]) % 2019

# log(ruiseki)

ans = 0
count = defaultdict(int)

for x in ruiseki:
    # log(count[x])
    ans += count[x]
    count[x] += 1
# log(count)
print(ans)
# Original solution
from collections import defaultdict
# from sys import stdin
# input = stdin.readline


def main():
  # S = input()[-1:0:-1]
  S = input()[::-1]
  MOD = 2019

  # dp = [0]*(len(S)+1)
  # dp[0] = 0
  dic = [0]*2019
  dic[0] = 1

  ten = 1
  pre = 0
  for i, s in enumerate(S):
    # dp[i] = (dp[i-1] + ten*int(s)) % MOD
    pre = (pre + ten*int(s)) % MOD
    dic[pre] += 1
    ten *= 10

  sum_ = 0
  # for sup in dp:
  #   dic[sup] += 1

  for v in dic:
    sum_ += v*(v-1)//2

  print(sum_)


if(__name__ == '__main__'):
  main()


# Optimized solution
def main():
  # S = input()[-1:0:-1]
  S = input()[::-1]
  MOD = 2019

  # dp = [0]*(len(S)+1)
  # dp[0] = 0
  dic = [0]*2019
  dic[0] = 1

  ten = 1
  pre = 0
  for i, s in enumerate(S):
    # dp[i] = (dp[i-1] + ten*int(s)) % MOD
    pre = (pre + ten*int(s)) % MOD
    dic[pre] += 1
    ten *= 10
    ten %= MOD

  sum_ = 0
  # for sup in dp:
  #   dic[sup] += 1

  for v in dic:
    sum_ += v*(v-1)//2

  print(sum_)


if(__name__ == '__main__'):
  main()
# Original solution
import sys
from math import sqrt, gcd, ceil, log
from bisect import bisect
from collections import defaultdict
inp = sys.stdin.readline
read = lambda: list(map(int, inp().strip().split()))

# sys.setrecursionlimit(10**6)



def solve():
	s = inp().strip();# dic = defaultdict(int)
	sett = set(); sett.add(0)
	ans = 0; cum = 0
	for i in range(len(s)-1, -1, -1):

		cum += (int(s[i])*(10**(len(s)-i-1)% 2019)) % 2019
		cum %= 2019
		# print((int(s[i])*(10**(len(s)-i-1)% 2019)) % 2019, i, cum)
		if cum in sett:
			ans += 1
		sett.add(cum)
	# print(sett)
	print(ans)






if __name__ == "__main__":
	solve()

# Optimized solution
import sys
from math import sqrt, gcd, ceil, log
from bisect import bisect
from collections import defaultdict
inp = sys.stdin.readline
read = lambda: list(map(int, inp().strip().split()))

# sys.setrecursionlimit(10**6)



def solve():
	s = inp().strip();
	dic = defaultdict(int); dic[0] = 1
	# sett.add(0)
	ans = 0; cum = 0
	for i in range(len(s)-1, -1, -1):
		cum += (int(s[i])*pow(10, (len(s)-i-1), 2019)) % 2019
		cum %= 2019
		dic[cum] += 1
	# print(dic)
	for i in dic:
		ans += ((dic[i])*(dic[i]-1))//2
	print(ans)






if __name__ == "__main__":
	solve()
# Original solution
import sys

S = sys.stdin.readline().strip()

N = 2019
L = len(S)
dp = [[0 for _ in range(N)] for _ in range(L) ]
for i in range(L):
    t = int(S[i])
    dp[i][t] = 1

    for j in range(N):
        dp[i][(j*10 + t)%N] += dp[i-1][j]

res = 0
for i in range(L):
    res += dp[i][0]
print(res)

# Optimized solution
import sys

S = sys.stdin.readline().strip()

N = 2019
L = len(S)
curr = 0
seen = {}
INV = 210
seen[curr] = 1
for i in range(L):
    curr = (curr * 10 + int(S[i])) % N
    t = (curr * pow(10, L-i, N)) %N
    if t not in seen: seen[t] = 0
    seen[t] += 1

res = 0
for i in range(N):
    if i not in seen: continue
    t = seen[i]
    res += t * (t-1)//2
print(res)
# Original solution
import re
import sys

s = sys.stdin.buffer.readline().rstrip().decode()
ans = 0

for i in range(1, 200001):
    tmp = str(2019*i)
    if tmp in s:
        index = -1
        while True:
            index = s.find(tmp, index + 1)
            if index == -1:
                break
            ans += 1
    if int(tmp) > int(s):
        break
print(ans)


# Optimized solution
import sys

s = sys.stdin.buffer.readline().rstrip().decode()
MOD = 2019
ans = [1] + [0 for i in range(MOD)]
t = 1
r = 0
for i in reversed(s):
    r = (r + int(i)*t) % MOD
    t = t*10%2019
    ans[r] += 1
print((sum([m*(m-1)//2 for m in ans])))
# Original solution
from collections import Counter
import sys
read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines

def main():
    S = readline().strip()[::-1]
    N = len(S)

    a = [0]
    s = 0
    for i in range(N):
        s += int(S[i]) * pow(10, i, 2019)
        a.append(s % 2019)
    
    t = Counter(a)

    ans = 0
    for _, v in list(t.items()):
        ans += v * (v-1) // 2
    
    print(ans)
    

if __name__ == "__main__":
    main()


# Optimized solution
import sys
read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines

def main():
    S = [int(i) for i in readline().strip()[::-1]]

    a = {}
    a[0] = 1
    t = 0
    x = 1
    for s in S:
        t += s * x
        t %= 2019
        
        if t in a:
            a[t] += 1
        else:
            a[t] = 1

        x *= 10
        x %= 2019
    
    ans = 0
    for v in list(a.values()):
        ans += v * (v-1) // 2
    
    print(ans)
    

if __name__ == "__main__":
    main()
# Original solution
import sys
input = sys.stdin.readline
mod = 2019
def main():
    s = tuple([int(x) for x in input().rstrip()])
    n = len(s)
    ans = 0
    d = {}
    T = 0
    T1 = 0
    for i in range(n):
        T1 = s[n-1-i]*10**i+T
        T = T1
        t = T%mod
        if t in d:
            d[t] += 1
        else:
            d[t] = 1
    for k in d:
        if k != 0:
            ans += d[k]*(d[k]-1)//2
        else:
            ans += d[k]
    print(ans)
if __name__ == "__main__":
    main()

# Optimized solution
import sys
input = sys.stdin.readline
mod = 2019
def main():
    s = input().rstrip()
    n = len(s)
    d = {}
    d[0] = 1
    ten = 1
    T = 0
    for x in reversed(s):
        T += ten*int(x)
        ten *= 10
        T %= mod
        ten %= mod
        if T in d:
            d[T] += 1
        else:
            d[T] = 1

    print((sum(i*(i-1)//2 for i in list(d.values()))))
if __name__ == "__main__":
    main()
# Original solution
# -*- coding: utf-8 -*-
import sys
sys.setrecursionlimit(10**9)
INF=10**18
MOD=2019
input=lambda: sys.stdin.readline().rstrip()
YesNo=lambda b: bool([print('Yes')] if b else print('No'))
YESNO=lambda b: bool([print('YES')] if b else print('NO'))
int1=lambda x:int(x)-1

def main():
    A=list(map(int,list(input())))
    N=len(A)
    d=[0]*2019
    for i in range(2019):
        d[i]=(i*10)%MOD
    dp=[[0]*2019 for _ in range(N+1)]
    ans=0
    for i,x in enumerate(A):
        for j in range(2019):
            dp[i+1][(d[j]+x)%MOD]+=dp[i][j]
        dp[i+1][x]+=1
        ans+=dp[i+1][0]
    print(ans)

    

if __name__ == '__main__':
    main()


# Optimized solution
# -*- coding: utf-8 -*-
import sys
from collections import defaultdict
sys.setrecursionlimit(10**9)
INF=10**18
MOD=2019
input=lambda: sys.stdin.readline().rstrip()
YesNo=lambda b: bool([print('Yes')] if b else print('No'))
YESNO=lambda b: bool([print('YES')] if b else print('NO'))
int1=lambda x:int(x)-1

def main():
    A=list(map(int,list(input())))
    N=len(A)
    d=[0]*2019
    for i in range(2019):
        d[i]=(i*10)%MOD
    dp=[defaultdict(int) for _ in range(N+1)]
    ans=0
    for i,x in enumerate(A):
        for j in dp[i]:
            dp[i+1][(d[j]+x)%MOD]+=dp[i][j]
        dp[i+1][x]+=1
        ans+=dp[i+1][0]
    print(ans)

    

if __name__ == '__main__':
    main()
# Original solution
# -*- coding: utf-8 -*-
import sys
from collections import defaultdict
sys.setrecursionlimit(10**9)
INF=10**18
MOD=2019
input=lambda: sys.stdin.readline().rstrip()
YesNo=lambda b: bool([print('Yes')] if b else print('No'))
YESNO=lambda b: bool([print('YES')] if b else print('NO'))
int1=lambda x:int(x)-1

def main():
    A=list(map(int,list(input())))
    N=len(A)
    d=[0]*2019
    for i in range(2019):
        d[i]=(i*10)%MOD
    dp=[defaultdict(int) for _ in range(N+1)]
    ans=0
    for i,x in enumerate(A):
        for j in dp[i]:
            dp[i+1][(d[j]+x)%MOD]+=dp[i][j]
        dp[i+1][x]+=1
        ans+=dp[i+1][0]
    print(ans)

    

if __name__ == '__main__':
    main()


# Optimized solution
# -*- coding: utf-8 -*-
import sys
sys.setrecursionlimit(10**9)
INF=10**18
MOD=2019
input=lambda: sys.stdin.readline().rstrip()
YesNo=lambda b: bool([print('Yes')] if b else print('No'))
YESNO=lambda b: bool([print('YES')] if b else print('NO'))
int1=lambda x:int(x)-1

def main():
    A=list(map(int,list(input())[::-1]))
    N=len(A)
    S=[0]*(N+1)
    for i in range(N):
        S[i+1]=(S[i]+A[i]*pow(10,i,MOD))%MOD
    l=[0]*2019
    ans=0
    for i in range(N+1):
        ans+=l[S[i]]
        l[S[i]]+=1
    print(ans)


if __name__ == '__main__':
    main()
# Original solution
from collections import Counter
s = str(eval(input()))

si = [0] * (len(s)+1) #mod2019の累積和用に
tmp = 0
for i in range(1,len(s)+1): #累積和の作成
    tmp += int(s[len(s)-i])%2019 * pow(10,i-1,2019)
    si[i] = tmp % 2019

c = Counter(si)
ans = 0
for b in list(c.values()):#aがb回出てきたよ
    ans += b*(b-1)//2

print(ans)


# Optimized solution
s = str(eval(input()))
cnt = [0]*2019
cnt[0] += 1

si = [0] * (len(s)+1) #mod2019の累積和用に
tmp = 0
for i in range(1,len(s)+1): #累積和の作成
    tmp += int(s[-i])%2019 * pow(10,i-1,2019)#ここでpowを使わないとTLEする
    si[i] = tmp % 2019
    cnt[si[i]] += 1

ans = 0
for b in cnt:#aがb回出てきたよ
    ans += b*(b-1)//2

print(ans)
# Original solution
import sys,bisect,math
sys.setrecursionlimit(15000)

s = sys.stdin.readline().rstrip()
cum = [0]*(len(s)+1)#cumulative sum
import collections
d = collections.defaultdict(int)
d[0] = 1
ret = 0
dig = 1
for i in range(len(s))[::-1]:
    cum[i]=(int(s[i])*dig+cum[i+1])%2019
    dig *= 10
    #cum[i+1]=int(s[i:])%2019
    if cum[i] in d:
        ret += d[cum[i]]
    d[cum[i]] += 1
#print(d,cum,ret)
print(ret)

# Optimized solution
# n = int(sys.stdin.readline())
import sys,bisect,math
sys.setrecursionlimit(15000)

s = sys.stdin.readline().rstrip()
cum = [0]*(len(s)+1)#cumulative sum
import collections
d = collections.defaultdict(int)
d[0] = 1
ret = 0
dig = 1
for i in range(len(s))[::-1]:
    cum[i]=(int(s[i])*dig+cum[i+1])%2019
    dig = (dig*10)%2019
    #cum[i+1]=int(s[i:])%2019
    if cum[i] in d:
        ret += d[cum[i]]
    d[cum[i]] += 1
#print(d,cum,ret)
print(ret)
# Original solution
import sys

dp=[[0]*2019 for _ in range(2)]
dig=[int(c) for c in sys.stdin.readline().strip()]
tab=[[0]*2019 for _ in range(10)]

for x in range(10):
    for i in range(2019):
        tab[x][i]=(i*10+x)%2019

p=0
cnt=0
for x in dig:
    np=(p+1)&1
    for i in range(2019):
        dp[np][tab[x][i]]=dp[p][i]
    dp[np][x]+=1
    p=np
    cnt+=dp[p][0]

print(cnt)

# Optimized solution
from collections import Counter
S=input()[::-1]

X=[0]
md=2019

for i,s in enumerate(S):
    X.append((X[-1]+int(s)*pow(10,i,md))%md)

C=Counter(X)
ans=0
for v in list(C.values()):
    ans+=v*(v-1)//2

print(ans)
# Original solution
import collections
s = list(map(int,input()))

h = {}
for jj in range(2019+1):
    for d in range(0,10):
        h[jj,d] = (10 * jj + d) % 2019

dp = collections.Counter()
count = 0
for j in range(len(s)):
    ndp = collections.Counter()
    ndp[s[j]] += 1
    for k in dp:
        ndp[h[(k,s[j])]] +=1
        #ndp[(10*k + s[j]) % 2019] += 1
    count += ndp[0]
    dp = ndp

print(count)




# Optimized solution
import collections
s = list(map(int,input()))

dp = [0] * 2019
count = 0
for j in range(len(s)):
    ndp = [0] * 2019
    ndp[s[j]] += 1
    for k in range(len(dp)):
        ndp[(10*k + s[j]) % 2019] += dp[k]
    count += ndp[0]
    dp = ndp[::]

print(count)
# Original solution
import collections
s = list(map(int,input()))

dp = [0] * 2019
count = 0
for j in range(len(s)):
    ndp = [0] * 2019
    ndp[s[j]] += 1
    for k in range(len(dp)):
        ndp[(10*k + s[j]) % 2019] += dp[k]
    count += ndp[0]
    dp = ndp[::]

print(count)




# Optimized solution
s = list(map(int,input()))
dp = [0] * 2019
count = 0
for j in range(len(s)):
    ndp = [0] * 2019
    ndp[s[j]] += 1
    for k in range(len(dp)):ndp[(10*k + s[j]) % 2019] += dp[k]
    count += ndp[0]
    dp = ndp

print(count)
# Original solution
from collections import defaultdict
from operator import mul
from functools import reduce


memo = {}


def cmb(n, r):
    if (n, r) in memo:
        return memo[(n, r)]
    r = min(n - r, r)
    if r == 0:
        return 1
    over = reduce(mul, list(range(n, n - r, -1)))
    under = reduce(mul, list(range(1, r + 1)))
    memo[(n, r)] = over // under
    return over // under


s = input()[::-1]
acc = [int(s[0])]
cntr = defaultdict(int)
for i, c in enumerate(s[1:], 1):
    if c == '0':
        continue
    next_mod = (acc[-1] + 10 ** i * int(c)) % 2019
    cntr[next_mod] += 1
    acc.append(next_mod)

ans = 0
for k, v in list(cntr.items()):
    if k == 0:
        ans += v
    if v > 1:
        ans += cmb(v, 2)
print(ans)


# Optimized solution
from collections import defaultdict


s = input()[::-1]
cntr = defaultdict(int)
cntr[0] += 1
tens = 1
n = 0
for c in s:
    n += tens * int(c) % 2019
    n %= 2019
    cntr[n] += 1
    tens = tens * 10 % 2019

ans = 0
for v in list(cntr.values()):
    if v > 1:
        ans += v * (v - 1) // 2
print(ans)