/*
  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
 |                                                                 |
 |   author : thanos1399     Language : C ++                         | 
 |   college : MSIT                                                | 
 | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |  
*/
#include <iostream>
#include <sstream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cctype>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <functional>
#include <bits/stdc++.h>
using namespace std ;
#define TEST            int t ; cin>>t; while(t--)
#define line            cout<<endl;
#define loop(i,a,b)     for(long long int i=a;i<b;i++)
#define loopIn(i,a,b)   for(long long int i=a;i<=b;i++)
#define MAX_SIZE        1000000
#define ff              first
#define ss              second
#define pb              push_back
#define ll              long long int  
#define mp              make_pair
#define vt              vector<tup>
#define vtt             vector<vt >
#define pii             pair<int,int>
#define vi              vector<int>
#define mii             map<int,int>
#define pqb             priority_queue<int>
#define pqs             priority_queue<int,vi,greater<int> >
#define setbits(x)      __builtin_popcountll(x)
#define zrobits(x)      __builtin_ctzll(x)
#define mod             1000000007
#define inf             1e18
#define ps(x,y)         fixed<<setprecision(y)<<x
#define mk(arr,n,type)  type *arr=new type[n];
void Sieve( int *prime , int n){for(int i=0;i<n;i++){prime[i] = 0;}for(int i=2;i<n;i++){prime[i] = 1 ;}for(int i=4;i<n;i+=2){prime[i] = 0;}for(int i=3;i<n;i++){if(prime[i]==1){for(int j=i*i;j<n;j+=i){prime[j] = 0;}}}return ;}
void input(){
    ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    #ifndef ONLINE_JUDGE
    freopen("/home/yash/Desktop/CPP/input.txt","r",stdin);
    freopen("/home/yash/Desktop/CPP/output.txt","w",stdout);
    #endif
}
ll inp;
int parent[101];
bool sortbysec(const pair<int,int> &a,const pair<int,int> &b) {return (a.second < b.second); } 
/*int find(int a)
{
    while(parent[a] > 0)
        a = parent[a];
 
    return a;
} */
class item{
    public:
        ll val , wt ;
};
 
void Union(int a , int b)
{
    parent[a] += parent[b];     //adding size of set b to set a
    parent[b] = a;              //making a , parent of new set
}
int find ( int node )
{
    if ( parent[node] < 0 )
        return node ;
 
    parent[node] = find( parent[node] ) ;
    return parent[node] ;
}

// Solution 1 
ll solve( vector<item> arr , ll n , ll W){
    ll dp[n+1][W+1];
    for(ll w = 0 ; w<=W ; w++){
        dp[1][w] =  0 ;
    }
    dp[1][arr[1].wt] = arr[1].val ;
    for(ll i = 2 ; i<= n ; i++){
        for( ll w = 0 ; w<=W ; w++){
            dp[i][w] = dp[i-1][w];
            if(arr[i].wt > w) continue ;
            dp[i][w] = max(dp[i][w] , arr[i].val + dp[i-1][w-arr[i].wt]);
        }
    }

  // return dp[n][W];
   return *max_element(dp[n] , dp[n] + W + 1 );
}
int solve1(vector<item> arr , ll n , ll W) 
{ 
   ll i, w; 
   ll K[n+1][W+1]; 
  
   // Build table K[][] in bottom up manner 
   for (i = 0; i <= n; i++) 
   { 
       for (w = 0; w <= W; w++) 
       { 
           if (i==0 || w==0) 
               K[i][w] = 0; 
           else if (arr[i-1].wt <= w) 
                 K[i][w] = max(arr[i-1].val + K[i-1][w-arr[i-1].wt],  K[i-1][w]); 
           else
                 K[i][w] = K[i-1][w]; 
       } 
   } 
  
   return K[n][W]; 
} 
int main() {
   // input();
    ll n , W ;
    cin >> n >> W ;
    vector<item> arr(n+1);
    for(ll i=1 ; i<=n ; i++){
        cin>>arr[i].wt>>arr[i].val;
    }
    ll ans = solve( arr , n , W );
    //ll ans2 = solve1( arr , n , W) ;
    cout<<ans<<endl;


    return 0;
}

Measured memory_bytes: 78336