// Original C++ solution (slower):
#include<bits/stdc++.h>

using namespace std;



typedef long long ll;

typedef vector<ll> vll;

typedef vector<vector<ll>> vvll;

typedef vector<vector<vector<ll>>> vvvll;

typedef vector<bool> vb;

typedef vector<vector<bool>> vvb;

typedef vector<vector<vector<bool>>> vvvb;

typedef pair<ll, ll> pll;

typedef vector<pll> vpll;

typedef vector<vpll> vvpll;

typedef vector<double> vd;

typedef vector<vd> vdd;



#define FOR(i,x,y) for(ll i=(ll)x; i<(ll)y; ++i)

#define REP(i,y) FOR(i, 0, y)

#define RFOR(i,x,y) for(ll i=(ll)x; i>=(ll)y; --i)

#define RREP(i,x) RFOR(i, x, 0)

#define ALL(a) a.begin(), a.end()

#define pb push_back

#define debug_print(x...) cerr << "line " << __LINE__ << " : "; debug_print_in(x);



template <typename First>

void debug_print_in(First first){

  cerr << first << endl;

  return;

}



template <typename First, typename... Rest>

void debug_print_in(First first, Rest... rest){

  cerr << first << " ";

  debug_print_in(rest...);

  return;

}



void IN(void){

  return;

}



template <typename First, typename... Rest>

void IN(First& first, Rest&... rest){

  cin >> first;

  IN(rest...);

  return;

}



template <typename First>

void OUT(First first){

  cout << first << endl;

  return;

}



template <typename First, typename... Rest>

void OUT(First first, Rest... rest){

  cout << first << " ";

  OUT(rest...);

  return;

}



template<class t, class u> void chmax(t&a,u b){if(a<b)a=b;};

template<class t, class u> void chmin(t&a,u b){if(a>b)a=b;};

int popcount(int t){return __builtin_popcount(t);} //GCC

int popcount(ll t){return __builtin_popcountll(t);} //GCC



template <typename T>

void vec_print(vector<T> VEC){

  REP(i, VEC.size()){

    cerr << VEC[i] << " ";

  }

  cerr << endl;

};



template <typename T>

void mat_print(vector<vector<T> > MAT){

  REP(i,MAT.size()){

    REP(j,MAT[i].size()){

      cerr << MAT[i][j] << " ";

    }

    cerr << endl;

  }

};



constexpr int INF = (1<<30);

constexpr ll INFLL = 1LL<<62;

constexpr long double EPS = 1e-12;

constexpr ll MOD = (ll)((1E+9)+7);



int main(){

  cin.tie(0); // cut the cin and cout (default, std::flush is performed after std::cin)

  ios::sync_with_stdio(false); // cut the iostream and stdio (DON'T endl; BUT "\n";)



  string S;

  IN(S);

  vll dp1(2019, 0);

  vll dp2(2019, 0);

  REP(i,S.size()){

    ll val = S[i]-'0';

    vll dp2_copy = dp2;

    REP(j,2019){

      ll n = (j*10+val)%2019;

      dp1[j] += dp2_copy[j];

      dp2[n] = dp2_copy[j];

    }

    dp2[val]++;

  }



  OUT(dp1[0]+dp2[0]);



  return 0;

}


// Optimized solution to the same problem (faster):
#include<bits/stdc++.h>

using namespace std;



typedef long long ll;

typedef vector<ll> vll;

typedef vector<vector<ll>> vvll;

typedef vector<vector<vector<ll>>> vvvll;

typedef vector<bool> vb;

typedef vector<vector<bool>> vvb;

typedef vector<vector<vector<bool>>> vvvb;

typedef pair<ll, ll> pll;

typedef vector<pll> vpll;

typedef vector<vpll> vvpll;

typedef vector<double> vd;

typedef vector<vd> vdd;



#define FOR(i,x,y) for(ll i=(ll)x; i<(ll)y; ++i)

#define REP(i,y) FOR(i, 0, y)

#define RFOR(i,x,y) for(ll i=(ll)x; i>=(ll)y; --i)

#define RREP(i,x) RFOR(i, x, 0)

#define ALL(a) a.begin(), a.end()

#define pb push_back

#define debug_print(x...) cerr << "line " << __LINE__ << " : "; debug_print_in(x);



template <typename First>

void debug_print_in(First first){

  cerr << first << endl;

  return;

}



template <typename First, typename... Rest>

void debug_print_in(First first, Rest... rest){

  cerr << first << " ";

  debug_print_in(rest...);

  return;

}



void IN(void){

  return;

}



template <typename First, typename... Rest>

void IN(First& first, Rest&... rest){

  cin >> first;

  IN(rest...);

  return;

}



template <typename First>

void OUT(First first){

  cout << first << endl;

  return;

}



template <typename First, typename... Rest>

void OUT(First first, Rest... rest){

  cout << first << " ";

  OUT(rest...);

  return;

}



template<class t, class u> void chmax(t&a,u b){if(a<b)a=b;};

template<class t, class u> void chmin(t&a,u b){if(a>b)a=b;};

int popcount(int t){return __builtin_popcount(t);} //GCC

int popcount(ll t){return __builtin_popcountll(t);} //GCC



template <typename T>

void vec_print(vector<T> VEC){

  REP(i, VEC.size()){

    cerr << VEC[i] << " ";

  }

  cerr << endl;

};



template <typename T>

void mat_print(vector<vector<T> > MAT){

  REP(i,MAT.size()){

    REP(j,MAT[i].size()){

      cerr << MAT[i][j] << " ";

    }

    cerr << endl;

  }

};



constexpr int INF = (1<<30);

constexpr ll INFLL = 1LL<<62;

constexpr long double EPS = 1e-12;

constexpr ll MOD = (ll)((1E+9)+7);



string S;

ll N;

vll dp;



int main(){

  cin.tie(0); // cut the cin and cout (default, std::flush is performed after std::cin)

  ios::sync_with_stdio(false); // cut the iostream and stdio (DON'T endl; BUT "\n";)



  IN(S);

  N = S.size();

  dp.resize(2019, 0);



  reverse(ALL(S));

  ll shift = 1;

  dp[0] = 1;

  ll ans = 0;

  ll tmp = 0;

  REP(i,N){

    ll val = S[i]-'0';

    val *= shift;

    val %= 2019;

    val += tmp;

    val %= 2019;

    ans += dp[val];

    dp[val]++;

    //debug_print(val, (2019-val)%2019, ans);

    shift *= 10;

    shift %= 2019;

    tmp = val;

  }



  OUT(ans);



  return 0;

}


// Fastest known solution for this problem: