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

#include <cmath>

#include <algorithm>

#include <cfloat>

#include <stack>

#include <queue>

#include <vector>

#include <string>

#include <iostream>

#include <set>

#include <map>

#include <time.h>

typedef long long int ll;

typedef unsigned long long int ull;

#define BIG_NUM 2000000000

#define MOD 1000000007

#define EPS 0.000000001

using namespace std;





enum Type{

	FULL_MATCH,

	ELSE,

};



ll length,POW[16];

ll num_array[20];

ll dp[20][10000][2][2];



ll getNUM(ll pre_num,ll next){

	return (10*pre_num+next)%10000;

}



bool is_OK(ll number){

	if((number/1000)%10 != 5)return false;

	if(number-5000 <= 99 || number-5000 >= 200)return false;

	if(number%10 != 3)return false;

	return true;

}



ll recursive(ll pre_num,ll digit,Type type,bool is_completed){



	if(digit == length){

		if(is_completed)return 1;

		else{

			return 0; //G数が成立しないならreturn 0;

		}

	}



	if(dp[digit][pre_num][type][is_completed] != -1){

		return dp[digit][pre_num][type][is_completed]; //計算済ならreturn

	}



	if(is_completed == true && type == ELSE){

		return dp[digit][pre_num][type][is_completed] = POW[length-digit];

	}



	ll ret = 0;

	ll limit;

	if(type == FULL_MATCH){

		limit = num_array[digit]-1;

	}else{

		limit = 9;

	}



	ll tmp;



	for(int next = 0; next <= limit; next++){

		tmp =  getNUM(pre_num,next);

		ret += recursive(tmp,digit+1,ELSE,is_completed||is_OK(tmp));

	}



	if(type == FULL_MATCH){

		tmp = getNUM(pre_num,num_array[digit]);

		ret += recursive(tmp,digit+1,FULL_MATCH,is_completed||is_OK(tmp));

	}



	return dp[digit][pre_num][type][is_completed] = ret;

}





int main(){



	for(int i = 0; i < 16; i++){

		POW[i] = pow(10,i);

	}



	ll N;

	scanf("%lld",&N);



	if(N <= 5102){

		printf("0\n");

		return 0;

	}



	stack<ll> S;



	//Nを桁別に分解する

	while(N > 0){

		S.push(N%10);

		N /= 10;

	}



	ll index = 0;



	while(!S.empty()){

		num_array[index++] = S.top();

		S.pop();

	}



	length = index;



	for(int digit = 0; digit <= length-1; digit++){

		for(int pre_num = 0; pre_num <= 9999; pre_num++){

			for(int p = 0; p <= 1; p++){

				for(int k = 0; k <= 1; k++){

					dp[digit][pre_num][p][k] = -1;

				}

			}

		}

	}



	printf("%lld\n",recursive(0,0,FULL_MATCH,false));



	return 0;

}






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

#include <cmath>

#include <algorithm>

#include <cfloat>

#include <stack>

#include <queue>

#include <vector>

#include <string>

#include <iostream>

#include <set>

#include <map>

#include <time.h>

typedef long long int ll;

typedef unsigned long long int ull;

#define BIG_NUM 2000000000

#define MOD 1000000007

#define EPS 0.000000001

using namespace std;





enum Type{

	FULL_MATCH,

	ELSE,

};



ll length,POW[16];

ll num_array[20];

ll memo[18][2]; //memo[初めてG数が成立した桁数][先頭桁から、Nと数が一致し続けているか] = 残りの桁を埋める場合の数

//ll dp[18][1000][5][2]; //dp[桁数][pre_num][パターンと一致している文字の数][先頭からNと数が一致し続けているか] = 場合の数

ll dp[18][10][5][2];



ll getNUM(ll pre_num,ll next){

	//return (10*pre_num+next)%1000;

	return next;

}



ll recursive(ll pre_num,ll digit,Type type, ll pattern_match_num){



	if(pattern_match_num == 4){ //digit-1桁目でG数が成立した場合



		return memo[digit-1][type]; //残りの桁を埋める場合の数をreturn

	}



	if(digit == length)return 0; //G数が成立しないならreturn 0;



	if(dp[digit][pre_num][pattern_match_num][type] != -1){

		return dp[digit][pre_num][pattern_match_num][type]; //計算済ならreturn

	}



	ll ret = 0;

	ll limit;

	if(type == FULL_MATCH){

		limit = num_array[digit]-1;

	}else{

		limit = 9;

	}



	for(int next = 0; next <= limit; next++){

		switch(pattern_match_num){

		case 0:

			if(next == 5){

				ret += recursive(getNUM(pre_num,next),digit+1,ELSE,1);

			}else{

				ret += recursive(getNUM(pre_num,next),digit+1,ELSE,0);

			}

			break;

		case 1:

			if(next == 1){

				ret += recursive(getNUM(pre_num,next),digit+1,ELSE,2);

			}else{

				if(next == 5){

					ret += recursive(getNUM(pre_num,next),digit+1,ELSE,1);

				}else{

					ret += recursive(getNUM(pre_num,next),digit+1,ELSE,0);

				}

			}

			break;

		case 2:

			ret += recursive(getNUM(pre_num,next),digit+1,ELSE,3);

			break;

		case 3:

			if(next == 3){

				ret += recursive(getNUM(pre_num,next),digit+1,ELSE,4);

			}else{



				if(next == 5){

					ret += recursive(getNUM(pre_num,next),digit+1,ELSE,1);

				}else{

					if(pre_num == 5 && next == 1){ //★★コーナーケース★★

						ret += recursive(getNUM(pre_num,next),digit+1,ELSE,2);

					}else{

						ret += recursive(getNUM(pre_num,next),digit+1,ELSE,0);

					}

				}

			}

			break;

		}

	}



	if(type == FULL_MATCH){

		switch(pattern_match_num){

		case 0:

			if(num_array[digit] == 5){

				ret += recursive(getNUM(pre_num,num_array[digit]),digit+1,FULL_MATCH,1);

			}else{

				ret += recursive(getNUM(pre_num,num_array[digit]),digit+1,FULL_MATCH,0);

			}

			break;

		case 1:

			if(num_array[digit] == 1){

				ret += recursive(getNUM(pre_num,num_array[digit]),digit+1,FULL_MATCH,2);

			}else{

				if(num_array[digit] == 5){

					ret += recursive(getNUM(pre_num,num_array[digit]),digit+1,FULL_MATCH,1);

				}else{

					ret += recursive(getNUM(pre_num,num_array[digit]),digit+1,FULL_MATCH,0);

				}

			}

			break;

		case 2:

			ret += recursive(getNUM(pre_num,num_array[digit]),digit+1,FULL_MATCH,3);

			break;

		case 3:

			if(num_array[digit] == 3){

				ret += recursive(getNUM(pre_num,num_array[digit]),digit+1,FULL_MATCH,4);

			}else{

				if(num_array[digit] == 5){

					ret += recursive(getNUM(pre_num,num_array[digit]),digit+1,FULL_MATCH,1);

				}else{

					if(pre_num == 5 && num_array[digit] == 1){ //★★コーナーケース★★

						ret += recursive(getNUM(pre_num,num_array[digit]),digit+1,FULL_MATCH,2);

					}else{

						ret += recursive(getNUM(pre_num,num_array[digit]),digit+1,FULL_MATCH,0);

					}

				}

			}

			break;

		}

	}

	return dp[digit][pre_num][pattern_match_num][type] = ret;

}





int main(){



	for(int i = 0; i < 16; i++){ //最速の成立は3桁目(0オリジン) よって、最大残桁は14

		POW[i] = pow(10,i);

	}



	ll N;

	scanf("%lld",&N);



	if(N <= 5102){

		printf("0\n");

		return 0;

	}



	stack<ll> S;



	ll tmp = N;



	//Nを桁別に分解する

	while(tmp > 0){

		S.push(tmp%10);

		tmp /= 10;

	}



	ll index = 0;



	while(!S.empty()){

		num_array[index++] = S.top();

		S.pop();

	}



	length = index;

	int rest_digit;



	//先頭からの一致がfalseの場合のmemoを埋める

	for(int digit = 3; digit <= length-1; digit++){

		rest_digit = length-(digit+1);

		memo[digit][ELSE] = POW[rest_digit];

	}



	//先頭からの一致がtrueの場合のメモを埋める

	for(int digit = 3; digit <= length-1; digit++){

		rest_digit = length-(digit+1);

		memo[digit][FULL_MATCH] = (N%POW[rest_digit])+1; //+1は末尾0の分

	}



	for(int digit = 0; digit <= length-1; digit++){

		//for(int pre_num = 0; pre_num <= 999; pre_num++){

		for(int pre_num = 0; pre_num <= 9; pre_num++){

			for(int match_num = 0; match_num <= 4; match_num++){

				for(int p = 0; p <= 1; p++)dp[digit][pre_num][match_num][p] = -1;

			}

		}

	}



	printf("%lld\n",recursive(0,0,FULL_MATCH,0));



	return 0;

}




// Fastest known solution for this problem: