// Slower C++ solution:
#include<iostream>

#include<cstdio>

#include<cstring>

#include<cstdlib>

#include<algorithm>

#include<stack>

#include<queue>

#include<vector>

#include<set>

#include<string>

#include<cmath>

#include<map>

#include<bitset>

#include<utility>

//#include<unordered_map>

#ifdef LOCAL

#include"file.h"

#endif



using namespace std;



typedef long long LL;

typedef unsigned long long ULL;

const double eps = 1e-12;

const double Pi = 3.1415926535897932;

const int dir[4][2] = { -1,0,1,0,0,-1,0,1 };

//const int dir[8][2] = { -2,-1,-2,1,2,-1,2,1,-1,2,-1,-2,1,2,1,-2 };











const int maxn = 1e5 + 5;

LL f[maxn];





int main() {

#ifdef LOCAL

	fileopen();

#endif

	int n, C;

	scanf("%d%d", &n, &C);

	memset(f, -1, sizeof(f));

	f[0] = 0;

	for (int i = 1; i <= n; i++) {

		int w, v;

		scanf("%d%d", &w, &v);

		for (int i = C; i >= w; i--)if(f[i-w]!=-1) {

			f[i] = max(f[i], f[i - w] + v);

		}

	}

	LL ans = 0;

	for (int i = 0; i <= C; i++)ans = max(ans, f[i]);

	printf("%lld\n", ans);



#ifdef LOCAL

	fileclose();

#endif

	return 0;

}

// Faster C++ solution for the same problem (measured speedup: 1.7958142431932687x):
#include <iostream>

#include <vector>

#include <string>

#include <queue>

#include <stack>

#include <map>

#include <set>

#include <unordered_map>

#include <unordered_set>

#include <cmath>

#include <algorithm>

#include <bitset>  

using namespace std;



//======================================================

#define for1(i,n)  for (int i = 0; i < (int)(n); ++i)

#define for2(i,n)  for (int i = 1; i <=(int)(n); ++i)

#define forr1(i,n)  for (int i = n - 1 ;i <= 0; --i)

#define forr2(i,n)  for (int i = n  ;i < 0; --i)

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

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

#define clr(v,d)   memset(v, d, sizeof(v))

#define ull        unsigned long long

#define MP(a,b)	   make_pair(a,b)

#define S          second

#define F          first

#define PI         3.14159265359

#define ll         long long

#define sz(v)	   v.size()

#define pb         push_back

#define pp         pop_back

#define bgn        begin

#define N          100000+5

#define	MOD        1e9+7

#define inf        1e18

//======================================================

int dx[] = { 0,  0, 1, -1 ,  1,  -1,  1,  -1 };

int dy[] = { 1, -1, 0,  0 , -1,   1,  1,  -1 };

//======================================================

ll gcd(ll a, ll b) { return !b ? a : gcd(b, a % b); }

ll lcm(ll a, ll b) { return (a / gcd(a, b)) * b; }

ll power(ull a, ull b, ull ret = 1LL) {

	while (b--) ret = (ret * a);

	return ret;

}

//======================================================







int weights[100+9];

long long benefit[100+9];

int n , kpWeight;

long long dp[100 + 9][100000 + 9];



long long  knapSack(int index , int reminderWeight)

{

	if (index == n)

		return 0;



	if (dp[index][reminderWeight] != -1)

	{

		return dp[index][reminderWeight];

	}



	long long leave = knapSack(index + 1, reminderWeight);



	long long take = 0;

	if (reminderWeight >= weights[index])

	{

		take = benefit[index] + knapSack(index + 1, reminderWeight - weights[index]);

	}

	return dp[index][reminderWeight] = max(leave, take);

}



int main()

{

	

	cin >> n >> kpWeight;

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

	{

		int a;

		long long b;

		cin >> a >> b;

		weights[i] = a;

		benefit[i] = b;

	}

	for (int i1 = n - 1; i1 >= 0; i1--)

	{

		for (int i2 = 0; i2 <= kpWeight; i2++)

		{

			if (i2 >= weights[i1])

			{

				dp[i1][i2] = max(benefit[i1] + dp[i1 + 1][i2 - weights[i1]], dp[i1 + 1][i2]);



			}

			else

			{

				dp[i1][i2] = dp[i1 + 1][i2];



			}

		}

	}

	cout << dp[0][kpWeight];

}