import sys

sys.setrecursionlimit(1000000000)

import math

from math import gcd

def lcm(a, b): return a * b // gcd(a, b)

from itertools import count, permutations, chain

from functools import lru_cache

from collections import deque, defaultdict

from pprint import pprint

ii = lambda: int(eval(input()))

mis = lambda: list(map(int, input().split()))

lmis = lambda: list(mis())

INF = float('inf')

N1097 = 10**9 + 7



def meg(f, ok, ng):

    while abs(ok-ng)>1:

        mid = (ok+ng)//2

        if f(mid):

            ok=mid

        else:

            ng=mid

    return ok



def get_inv(n, modp):

    return pow(n, modp-2, modp)



def factorials_list(n, modp):    # 10**6

    fs = [1]

    for i in range(1, n+1):

        fs.append(fs[-1] * i % modp)

    return fs



def invs_list(n, fs, modp):     # 10**6

    invs = [get_inv(fs[-1], modp)]

    for i in range(n, 1-1, -1):

        invs.append(invs[-1] * i % modp)

    invs.reverse()

    return invs



def comb(n, k, modp):

    num = 1

    for i in range(n, n-k, -1):

        num = num * i % modp

    den = 1

    for i in range(2, k+1):

        den = den * i % modp

    return num * get_inv(den, modp) % modp



def comb_from_list(n, k, modp, fs, invs):   

    return fs[n] * invs[n-k] * invs[k] % modp



#



class UnionFindEx:

    def __init__(self, size):

        #正なら根の番号、負ならグループサイズ

        self.roots = [-1] * size

    def getRootID(self, i):

        r = self.roots[i]

        if r < 0:   #負なら根

            return i

        else:

            r = self.getRootID(r)

            self.roots[i] = r

            return r

    def getGroupSize(self, i):

        return -self.roots[self.getRootID(i)]

    def connect(self, i, j):

        r1, r2 = self.getRootID(i), self.getRootID(j)

        if r1 == r2:

            return False

        if self.getGroupSize(r1) < self.getGroupSize(r2):

            r1, r2 = r2, r1

        self.roots[r1] += self.roots[r2]    #サイズ更新

        self.roots[r2] = r1

        return True



Yes = 'Yes'

No = 'No'





def main():

    S = eval(input())

    d = [0]*2019

    dn = [0]*2019

    ans = 0

    for s in S:

        sn = int(s)

        dn[sn] += 1

        for i in range(2019):

            dn[(i*10+sn)%2019] += d[i]

        d, dn = dn, d

        for i in range(2019):

            dn[i] = 0

        ans += d[0]

    print(ans)













main()



'''

[point 1]

1817181712114 の部分 "18171"について考える...



    181710000 / 10000 ≡ 0 (MOD 2019) ならば、2019の倍数

    181710000 ≡ 0 (MOD 2019) でよい



[point 2]

    181710000

    =

    181712114

    -

         2114



    なので、特定区間の値 は 累積和の差 から瞬時に求められる。

    さらに、181710000 ≡ 0 (MOD 2019) を考えると、



    0 ≡ 181712114 - 2114

    → 181712114 ≡ 2114



    となる。

    結局の所、MOD2019において合同な累積和のペアの数の数え上げ。

'''



from collections import defaultdict



def gen_10exp_mod(n, mod):

    a = 1

    yield a

    for _ in range(1, n):

        a = (a*10) % mod

        yield a



def main():

    MOD = 2019

    S = input()[::-1]

    # 桁ごとの実際の値を計算 (MOD)

    A = [int(s)*n % MOD for s, n in zip(S, gen_10exp_mod(len(S), MOD))]

    # 累積和を計算

    ACC = [0]

    for a in A:

        ACC.append((ACC[-1] + a) % MOD)

    # ペア数え上げ

    d = defaultdict(int)

    for acc in ACC:

        d[acc] += 1

    ans = sum(v*(v-1)//2 for v in list(d.values()))

    print(ans)





main()

import sys

sys.setrecursionlimit(1000000000)
import math
from math import gcd


def lcm(a, b):
    return a * b // gcd(a, b)


from itertools import count, permutations, chain
from functools import lru_cache
from collections import deque, defaultdict
from pprint import pprint

ii = lambda: int(eval(input()))
mis = lambda: list(map(int, input().split()))
lmis = lambda: list(mis())
INF = float("inf")
N1097 = 10**9 + 7


def meg(f, ok, ng):
    while abs(ok - ng) > 1:
        mid = (ok + ng) // 2
        if f(mid):
            ok = mid
        else:
            ng = mid
    return ok


def get_inv(n, modp):
    return pow(n, modp - 2, modp)


def factorials_list(n, modp):  # 10**6
    fs = [1]
    for i in range(1, n + 1):
        fs.append(fs[-1] * i % modp)
    return fs


def invs_list(n, fs, modp):  # 10**6
    invs = [get_inv(fs[-1], modp)]
    for i in range(n, 1 - 1, -1):
        invs.append(invs[-1] * i % modp)
    invs.reverse()
    return invs


def comb(n, k, modp):
    num = 1
    for i in range(n, n - k, -1):
        num = num * i % modp
    den = 1
    for i in range(2, k + 1):
        den = den * i % modp
    return num * get_inv(den, modp) % modp


def comb_from_list(n, k, modp, fs, invs):
    return fs[n] * invs[n - k] * invs[k] % modp


#
class UnionFindEx:
    def __init__(self, size):
        # 正なら根の番号、負ならグループサイズ
        self.roots = [-1] * size

    def getRootID(self, i):
        r = self.roots[i]
        if r < 0:  # 負なら根
            return i
        else:
            r = self.getRootID(r)
            self.roots[i] = r
            return r

    def getGroupSize(self, i):
        return -self.roots[self.getRootID(i)]

    def connect(self, i, j):
        r1, r2 = self.getRootID(i), self.getRootID(j)
        if r1 == r2:
            return False
        if self.getGroupSize(r1) < self.getGroupSize(r2):
            r1, r2 = r2, r1
        self.roots[r1] += self.roots[r2]  # サイズ更新
        self.roots[r2] = r1
        return True


Yes = "Yes"
No = "No"


def main():
    S = eval(input())
    d = [0] * 2019
    dn = [0] * 2019
    ans = 0
    for s in S:
        sn = int(s)
        dn[sn] += 1
        for i in range(2019):
            dn[(i * 10 + sn) % 2019] += d[i]
        d, dn = dn, d
        for i in range(2019):
            dn[i] = 0
        ans += d[0]
    print(ans)


main()

"""
[point 1]
1817181712114 の部分 "18171"について考える...
    181710000 / 10000 ≡ 0 (MOD 2019) ならば、2019の倍数
    181710000 ≡ 0 (MOD 2019) でよい
[point 2]
    181710000
    =
    181712114
    -
         2114
    なので、特定区間の値 は 累積和の差 から瞬時に求められる。
    さらに、181710000 ≡ 0 (MOD 2019) を考えると、
    0 ≡ 181712114 - 2114
    → 181712114 ≡ 2114
    となる。
    結局の所、MOD2019において合同な累積和のペアの数の数え上げ。
"""
from collections import defaultdict


def gen_10exp_mod(n, mod):
    a = 1
    yield a
    for _ in range(1, n):
        a = (a * 10) % mod
        yield a


def main():
    MOD = 2019
    S = input()[::-1]
    # 桁ごとの実際の値を計算 (MOD)
    A = [int(s) * n % MOD for s, n in zip(S, gen_10exp_mod(len(S), MOD))]
    # 累積和を計算
    ACC = [0]
    for a in A:
        ACC.append((ACC[-1] + a) % MOD)
    # ペア数え上げ
    d = defaultdict(int)
    for acc in ACC:
        d[acc] += 1
    ans = sum(v * (v - 1) // 2 for v in list(d.values()))
    print(ans)


main()

-import sys - -sys.setrecursionlimit(1000000000) -import math -from math import gcd +""" +[point 1] +1817181712114 の部分 "18171"について考える... +    181710000 / 10000 ≡ 0 (MOD 2019) ならば、2019の倍数 +    181710000 ≡ 0 (MOD 2019) でよい +[point 2] +    181710000 +    = +    181712114 +    - +         2114 +    なので、特定区間の値 は 累積和の差 から瞬時に求められる。 +    さらに、181710000 ≡ 0 (MOD 2019) を考えると、 +    0 ≡ 181712114 - 2114 +    → 181712114 ≡ 2114 +    となる。 +    結局の所、MOD2019において合同な累積和のペアの数の数え上げ。 +""" +from collections import defaultdict -def lcm(a, b): -    return a * b // gcd(a, b) - - -from itertools import count, permutations, chain -from functools import lru_cache -from collections import deque, defaultdict -from pprint import pprint - -ii = lambda: int(eval(input())) -mis = lambda: list(map(int, input().split())) -lmis = lambda: list(mis()) -INF = float("inf") -N1097 = 10**9 + 7 - - -def meg(f, ok, ng): -    while abs(ok - ng) > 1: -        mid = (ok + ng) // 2 -        if f(mid): -            ok = mid -        else: -            ng = mid -    return ok - - -def get_inv(n, modp): -    return pow(n, modp - 2, modp) - - -def factorials_list(n, modp):  # 10**6 -    fs = [1] -    for i in range(1, n + 1): -        fs.append(fs[-1] * i % modp) -    return fs - - -def invs_list(n, fs, modp):  # 10**6 -    invs = [get_inv(fs[-1], modp)] -    for i in range(n, 1 - 1, -1): -        invs.append(invs[-1] * i % modp) -    invs.reverse() -    return invs - - -def comb(n, k, modp): -    num = 1 -    for i in range(n, n - k, -1): -        num = num * i % modp -    den = 1 -    for i in range(2, k + 1): -        den = den * i % modp -    return num * get_inv(den, modp) % modp - - -def comb_from_list(n, k, modp, fs, invs): -    return fs[n] * invs[n - k] * invs[k] % modp - - -# -class UnionFindEx: -    def __init__(self, size): -        # 正なら根の番号、負ならグループサイズ -        self.roots = [-1] * size - -    def getRootID(self, i): -        r = self.roots[i] -        if r < 0:  # 負なら根 -            return i -        else: -            r = self.getRootID(r) -            self.roots[i] = r -            return r - -    def getGroupSize(self, i): -        return -self.roots[self.getRootID(i)] - -    def connect(self, i, j): -        r1, r2 = self.getRootID(i), self.getRootID(j) -        if r1 == r2: -            return False -        if self.getGroupSize(r1) < self.getGroupSize(r2): -            r1, r2 = r2, r1 -        self.roots[r1] += self.roots[r2]  # サイズ更新 -        self.roots[r2] = r1 -        return True - - -Yes = "Yes" -No = "No" +def gen_10exp_mod(n, mod): +    a = 1 +    yield a +    for _ in range(1, n): +        a = (a * 10) % mod +        yield a -    S = eval(input()) -    d = [0] * 2019 -    dn = [0] * 2019 -    ans = 0 -    for s in S: -        sn = int(s) -        dn[sn] += 1 -        for i in range(2019): -            dn[(i * 10 + sn) % 2019] += d[i] -        d, dn = dn, d -        for i in range(2019): -            dn[i] = 0 -        ans += d[0] +    MOD = 2019 +    S = input()[::-1] +    # 桁ごとの実際の値を計算 (MOD) +    A = [int(s) * n % MOD for s, n in zip(S, gen_10exp_mod(len(S), MOD))] +    # 累積和を計算 +    ACC = [0] +    for a in A: +        ACC.append((ACC[-1] + a) % MOD) +    # ペア数え上げ +    d = defaultdict(int) +    for acc in ACC: +        d[acc] += 1 +    ans = sum(v * (v - 1) // 2 for v in list(d.values()))