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

//#include <ext/pb_ds/assoc_container.hpp>

//using namespace __gnu_pbds;

using namespace std;

 

#define ff              first

#define ss              second

#define int             long long

#define ll              long long 

#define pb              push_back

#define pii             pair<int,int>

#define vi              vector<int>

#define mii             map<int,int>

#define pqb             priority_queue<int>

#define pqs             priority_queue<int,vi,greater<int> >

#define setbits(x)      __builtin_popcountll(x)

#define zerobits(x)      __builtin_ctzll(x)

#define mod             998244353

#define Mod             1000000007

#define inf             1e18

#define ps(x,y)         fixed<<setprecision(y)<<x

#define mk(arr,n,type)  type *arr=new type[n];

#define w(x)            int x; cin>>x; while(x--)

#define vpii            vector<pair<int,int> >

#define all(x)          x.begin(),x.end()

#define gcd(m,n)        __gcd(m,n)   

#define matrixprint(arr,a,b,c,d) for(int i=a;i<=c;i++){for(int j=b;j<=d;j++){cout<<arr[i][j]<<" ";}cout<<"\n";}

 

 

template<int D, typename T>

struct Vec : public vector<Vec<D - 1, T>> {

  static_assert(D >= 1, "Vector dimension must be greater than zero!");

  template<typename... Args>

  Vec(int n = 0, Args... args) : vector<Vec<D - 1, T>>(n, Vec<D - 1, T>(args...)) {

  }

};

template<typename T>

struct Vec<1, T> : public vector<T> {

  Vec(int n = 0, const T& val = T()) : vector<T>(n, val) {

  }

};

 

 

#define TRACE

#ifdef TRACE

#define deb(...) __f(#__VA_ARGS__, __VA_ARGS__)

    template <typename Arg1>

    void __f(const char* name, Arg1&& arg1){

        cout << name << " : " << arg1 << std::endl;

    }

    template <typename Arg1, typename... Args>

    void __f(const char* names, Arg1&& arg1, Args&&... args){

        const char* comma = strchr(names + 1, ','); cout.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);

    }

#else

#define deb(...)

#endif

 

void fast()

{

	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);

//#ifndef ONLINE_JUDGE

//	freopen("input.txt", "r", stdin);

//	freopen("output.txt", "w", stdout);

//#endif

}

 

//////////////////////////////code//////////////////////////////

 

int32_t main()

{

  fast();

  

  string s;

  cin>>s;

  int n=s.size();

  

  int dp[2019]={0},temp[2019]={0};

  int ans=0;

  

  for(int i=0;i<n;i++)

  {  

    temp[s[i]-'0']++;

    

    for(int j=0;j<2019;j++)

    {

    	int curr = (j*10+s[i]-'0')%2019;

    	

    	temp[curr]+=dp[j];

    }

    

    for(int j=0;j<2019;j++)

    dp[j]=temp[j];

    

    memset(temp,0,sizeof(temp));

    

    ans+=dp[0];

    

   }

  

  cout<<ans;

  

 

}

// Optimized solution to the same problem (faster):
#include <iostream>

#include <string>

#include <vector>

#include <bits/stdc++.h>

#define ll long long



using namespace std;



int gcd(int x, int y) { return (x % y)? gcd(y, x % y): y; }



int main(){

    string S; cin >> S;

    vector<ll> cnt(2019, 0);

    ll sum = 0;

    ll d = 1;

    ll ans = 0;



    cnt[0]++;



    for (ll i = S.length(); i > 0; i--){

        sum += (S[i-1] - '0')*d;

        sum %= 2019;

        d *= 10;

        d %= 2019;

        cnt[sum]++;

    }



    for (ll i = 0; i < cnt.size(); i++){

        ans += cnt[i]*(cnt[i]-1) / 2;

    }

    

    cout << ans << endl;



    return 0;

    

}

// Fastest known solution for this problem: