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

#include<unordered_set>

#include<unordered_map>

#include <algorithm> 

#include <iostream>

#include <string>

#include <cmath>

using namespace std;

#define ll long long

#define rep(i, n) for (ll i = 0; i < (n); i++)

#define FOR(i,a,b) for(ll i=(a);i<(b);i++)

#define FORR(i,a,b)for(ll i=(a);i<=(b);i++)

#define repR(i,n) for(ll i=n;i>=0;i--)

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

#define rall(v)(v).rbegin(),(v).rend()

#define F first

#define S second

#define pb push_back

#define pu push

#define COUT(x) cout<<(x)<<endl

#define PQ priority_queue<ll>

#define PQR priority_queue<ll,vector<ll>,greater<ll>>

#define YES(n) cout << ((n) ? "YES" : "NO"  ) << endl

#define Yes(n) cout << ((n) ? "Yes" : "No"  ) << endl

#define mp make_pair

#define maxs(x,y) (x = max(x,y))

#define mins(x,y) (x = min(x,y))

#define sz(x) (ll)(x).size()

typedef pair<int,int> pii;

typedef pair<ll,ll> pll;

const ll MOD = 1000000007LL;

const ll INF = 1LL << 60;

using vll = vector<ll>;

using vb = vector<bool>;

using vvb = vector<vb>;

using vvll = vector<vll>;

using vstr = vector<string>;

using pll = pair<ll, ll>;

using vc = vector<char>;

using vvc = vector<vc>;

template<class T> inline bool chmax(T& a, T b) { 

 if (a < b) { a = b; return true; } return false; 

}

template<class T> inline bool chmin(T& a, T b) {

 if (a > b) { a = b; return true; } return false; 

}

ll dx[4]={0,1,0,-1};

ll dy[4]={1,0,-1,0};

int main(){

  ll n;

  string s;

  cin>>s;

  n=sz(s);

  vll a(2019);

  ll ans=0;

  rep(i,n){

    vll b(2019);

    rep(j,2019){

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

    }

    rep(j,2019){

      a[j]=b[j];

    }

    a[(s[i]-'0')]++;

    ans+=a[0];

  }

  COUT(ans);

}

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

#include<unordered_set>

#include<unordered_map>

#include <algorithm> 

#include <iostream>

#include <string>

#include <cmath>

using namespace std;

#define ll long long

#define rep(i,n) for (ll i = 0; i < (n); i++)

#define FOR(i,a,b) for(ll i=(a);i<(b);i++)

#define FORR(i,a,b)for(ll i=(a);i<=(b);i++)

#define repR(i,n) for(ll i=n;i>=0;i--)

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

#define rall(v)(v).rbegin(),(v).rend()

#define F first

#define S second

#define pb push_back

#define pu push

#define COUT(x) cout<<(x)<<"\n"

#define PQ priority_queue<ll>

#define PQR priority_queue<ll,vector<ll>,greater<ll>>

#define YES(n) cout << ((n) ? "YES\n" : "NO\n"  )

#define Yes(n) cout << ((n) ? "Yes\n" : "No\n"  )

#define mp make_pair

#define sz(x) (ll)(x).size()

typedef pair<int,int> pii;

typedef pair<ll,ll> pll;

const ll MOD = 1000000007LL;

const ll INF = 1LL << 60;

using vll = vector<ll>;

using vb = vector<bool>;

using vvb = vector<vb>;

using vvll = vector<vll>;

using vstr = vector<string>;

using vc = vector<char>;

using vvc = vector<vc>;

template<class T> inline bool chmax(T& a, T b) { 

 if (a < b) { a = b; return true; } return false; 

}

template<class T> inline bool chmin(T& a, T b) {

 if (a > b) { a = b; return true; } return false; 

}

ll dx[4]={0,1,0,-1};

ll dy[4]={1,0,-1,0};

int main(){

  string s;

  cin>>s;

  ll n=sz(s);

  vll d(n+1);

  ll ten=1;

  for(int i=n-1;i>=0;i--){

    ll a=ten*(s[i]-'0')%2019;

    d[i]=(d[i+1]+a)%2019;

    ten*=10; ten%=2019;

  }

  map<ll,ll> p;

  ll ans=0;

  rep(i,n+1){

    p[d[i]]++;

  }

  for(auto u:p){

    ans+=u.S*(u.S-1)/2;

  }

  COUT(ans);

}

// Fastest known solution for this problem: