#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp> 
using namespace std;
//using namespace __gnu_pbds;
#define rep(i,a,b) for(i=(a);i<=(b);i++)
#define ll long long
#define pll pair<ll, ll>
#define pii pair<int,int>
#define pb push_back
#define F first
#define S second
#define mod 1000000007
#define maxn 100005
#define inf 1e18
#define boost ios::sync_with_stdio(false);cin.tie(0)
#define fr freopen("source.txt","r",stdin),freopen("output.txt","w",stdout)
#define SET(a,b) memset(a,b,sizeof(a))
#define deb(x) cout << #x << "=" << x << endl
#define deb2(x, y) cout << #x << "=" << x << "," << #y << "=" << y << endl
#define all(x) x.begin(), x.end()
//template<typename T>
//using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
template<class A, class B> ostream& operator << (ostream& out, const pair<A, B> &a) {
	return out <<  "(" << a.F << ", " << a.S << ")";
}
 
template<class A> ostream& operator << (ostream& out, const vector<A> &a) {
	out << "[";
	for (auto it = a.begin(); it != a.end(); ++it) {
		if (it != a.begin())
			out << ", ";
		out << *it;
	}
	return out << "]";
}
ll powermod(ll x,ll y){
	ll res=1;
	while(y>0){
		if(y&1)
		res=(res*x)%mod;

		y/=2;
		x=(x*x)%mod;
	}
	return res;
}
int main()
{
    boost;
    ll n,i,j,x,t,y,p;
	string s;
	cin>>s;
	n=s.size();
	p=2019;
	vector<ll>v(p+5,0);
	ll cur=1,sum=0;
	for(i=n-1;i>=0;i--){
		x=s[i]-'0';
		x%=p;
		x=(x*cur)%p;
		x=(x+sum)%p;
		v[x]++;
		sum=x%p;
		cur=(cur*10)%p;
	}
	ll ans=v[0];
	cur=1;
	sum=0;
	for(i=n-1;i>=0;i--){
		x=s[i]-'0';
		x%=p;
		x=(x*cur)%p;
		x=(x+sum)%p;
		v[x]--;	
		v[x]=max(v[x],0LL);
		ans+=v[x];
		sum=x%p;
		cur=(cur*10)%p;
	}
	ans=min(ans,n*(n+1)/2);
	cout<<ans<<"\n";
}
