// AddPrimeToN.cpp : アプリケーションのエントリ ポイントを定義します。
//

#include <iostream>
#include <cstdint>
#include <vector>
#include <cmath>
#include <algorithm>

typedef std::vector<std::uint64_t> DType;

//エラトステネスの篩型プライムエンカウンター。

template<class T = std::size_t>
class PrimeEncounterAnother {
public:
	typedef std::vector<bool> PrimeSet;
	typedef T Integer;

	PrimeEncounterAnother() {
		Clear();
	}

	bool Clear() {
		Primes.clear();
		if (Primes.size() == 0) {
			Primes.push_back(true);
			Primes.push_back(true);
			Searched = 1;
		}
		return true;
	}

	bool Search(const Integer& N) {
		if (Searched >= N) return false;
		Integer L = static_cast<Integer>(std::sqrt(N)) + 1;
		Primes.resize(N + 1);
		for (Integer i = 0; i < L; i++) {
			if (Primes[i] == true) continue;
			for (Integer j = (Searched / i) + 1; i*j <= N; j++) {
				if (j <= 1)continue;
				Primes[i*j] = true;
			}
		}
		Searched = N + 1;
		return true;
	}
	Integer IsSearched() {
		return Searched;
	}
	Integer Size() {
		return Primes.size();
	}
	bool operator [](const Integer& Idx) {
		return !Primes[Idx];
	}
protected:
	PrimeSet Primes;
	Integer Searched;
};

std::int64_t MakeHoge(std::uint64_t N) {
	PrimeEncounterAnother<std::uint64_t> P;
	DType D;
	P.Search(N);
	for (std::uint64_t i = 2; i < P.IsSearched(); i++) {
		if (P[i] == true)D.push_back(i);
	}

	std::vector<std::vector<std::int64_t>> DP(D.size()+2);
	for (auto& o : DP) {
		o.resize(N+2);
	}

	for (std::size_t j = 0; j < D.size(); j++) DP[D.size()][j] = 0;

	for (std::int64_t i = D.size()-1; i >= 0; i--) {
		for (std::int64_t j = 0; j <= N; j++) {
			if (j < D[i]) {
				DP[i][j] = DP[i + 1][j];
			}
			else {
				DP[i][j] = std::max(DP[i + 1][j], DP[i + 1][j - D[i]] + 1);
			}
		}
	}


	return DP[0][N];
}

int main()
{
	std::int64_t R;
	R=MakeHoge(2018);
	std::cout << R << std::endl;

    return 0;
}

