// DOMINIX --- CODEJAM TEMPLATE
/**
 *    GOOGLE CODEJAM 2020
 *    Author:  dominix
 **/


//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,avx,avx2")

#include "bits/stdc++.h"
#include <vector>
#include <set>
#include <map>
#include <string> 
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <utility>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <iomanip> 
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp> 
//setbase - cout << setbase (16)a; cout << 100 << endl; Prints 64
//setfill -   cout << setfill ('x') << setw (5); cout << 77 <<endl;prints xxx77
//setprecision - cout << setprecision (14) << f << endl; Prints x.xxxx
//cout.precision(x)  cout<<fixed<<val;  // prints x digits after decimal in val

using namespace std;
using namespace __gnu_pbds;

#define READ 		freopen("in.txt", "r", stdin)
#define WRITE  		freopen("out.txt", "w", stdout)
#define BOOST		ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define shandom_ruffle random_shuffle
#define debug(x) cout << "hi" << x
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define nl cout << '\n'
#define rtz return(0)
#define br break
#define fi first
#define se second
#define ALL(a) a.begin(),a.end()
#define SZ(a) ((int)a.size())
#define REP(i, n) for(int i = 0; i < ((int) n); ++i)
#define eb emplace_back
#define mp(a, b) make_pair(a,b)
#define unic_sort(c) (sort(c.begin(), c.end()), c.resize(distance(c.begin(), unique(c.begin(), c.end()))))
#define get_pos(c, x) (int)(lb(c.begin(),c.end(),x)-c.begin())
#define BS(a, x) binary_search(ALL(a), x)
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update> 
  
using ll = long long;
using ld = long double;
using ull = unsigned long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pdd = pair<ld, ld>;
using vi = vector<int>;
using vii = vector<vi>;
using vll = vector<ll>;
using vlll = vector<vll>;
using vpii = vector<pii>;
using mpii = map<int, int>;
using mpll = map<ll, ll>;
using stch = stack<char>;
using stvll = stack<vll>;
#define pqueue priority_queue< int >
#define pdqueue priority_queue< int, vi, greater< int > >
const ll nax = 1000*1007;
const ll mno = 1007;
const ll mod = 1e9 + 7;
const ll mxN = 1e5 + 5;
const ll inF = 1e18;
const ll rc = 64;
const ll MOD = 998244353; 
const double pi = acos(-1.0);

#define popcntL   __builtin_popcountll
#define popcnt    __builtin_popcount
inline bool checkBit(int N, int pos) {   return (bool)(N & (1 << pos));  } // check bit
inline int setBit(int N, int pos) {	return N = N | (1 << pos);  }// set bit
inline int unsetBit(int N, int pos) {	return N = ( N & ( ~( 1 << pos ) ) );   }// unset bit
inline int toggleBit(int N, int pos) { return N = ( N ^ (1 << pos) ); }// toggle bit

inline int add_self(int a, int b) {
    a += b; 
    if(a >= mod) a -= mod;
    return a;

}

inline int mul_self(int a, int b) { 
    return (a * 1LL * b) % mod;

}

inline int power_self(int a, int b) {
    int rt = 1; 
    while(b > 0) { 
        if(b & 1) rt = mul_self(rt, a);
        a = mul_self(a, a); 
        b >>= 1;
    } 
    return rt;
}

inline ll modMul(ll a, ll b,ll mod){
    ll ans = 0;
    a = a % mod;
    while (b > 0){
        if ( b % 2 )ans = (ans%mod+ a%mod) % mod;
        a = (a%mod * 2%mod) % mod;
        b /= 2;
    }
    return ans % mod;
}

inline ll powerMod(ll a,ll b,ll mod){
	if(b == 0) return 1LL % mod;
	ll x = powerMod(a, b / 2, mod);
	x = (x % mod * x % mod) % mod;
	if(b % 2 == 1) x = (x % mod * a % mod) % mod;
	return x % mod;
}

inline ll lcm( ll a,ll b ){
	ll g = __gcd(a, b);
	return ((a / g) * b);
}

ll fast_exp(int base, int exp) {
    if(exp == 1) return base;
    else {
        if(exp % 2 == 0) {
            ll base1 = pow(fast_exp(base, exp / 2), 2);
            if(base1 >= 1000000007) return (base1 % 1000000007);
            else return base1;
        }
        else {
            ll ans = (base*  pow(fast_exp(base, (exp - 1) / 2), 2));
            if(ans >= 1000000007) return (ans % 1000000007);
            else return ans;
        }
    }
} 

// ll n, m, k, t;
// ll a, b, c, d;
// int x[mxN], y[mxN];
ll dp[2][2020];
int rst[2000002];
int main() {
    BOOST;
    // READ;
    // WRITE;
/*  // ordered_set o_set; .// name of the pbds data_structure
    // o_set.insert(5); // o_set.insert(1); // o_set.insert(2); // insertions
    // It returns to an iterator to the kth element (counting from zero) in the set in O(logn) time.
    // cout << *(o_set.find_by_order(1)) << endl;   
    // Finding the number of elements strictly less than k=4. It returns to the number of items that are strictly smaller than our item k in O(logn) time.
    // cout << o_set.order_of_key(4) << endl; 
*/
    string s;
    cin >> s;
    for(int i = 1; i <= 100000; ++i) rst[i] = i % 2019;
    dp[0][(s[0] - '0')] = 1;
    ll ans = 0;
    int n = s.size();
    for(int i = 1; i < n; ++i) {
        for(int j = 0; j <= 2018; ++j) {
            int nxt = rst[j * 10 + (s[i] - '0')];
            dp[1][nxt] += dp[0][j];
        }
        ans += dp[1][0];
        memcpy(dp[0], dp[1], sizeof(dp[1]));
        dp[0][(s[i] - '0')]++;
        memset(dp[1], 0, sizeof(dp[1]));
    }
    cout << ans; 	
  rtz;
}

Measured memory_bytes: 4108