// Slower C++ solution:
#include<bits/stdc++.h>

//#pragma GCC optimize("Ofast")

//#pragma GCC target("avx,avx2,fma")



using namespace std;



typedef long long ll;



//#include <ext/pb_ds/assoc_container.hpp>

//#include <ext/pb_ds/tree_policy.hpp>

//using namespace __gnu_pbds;

//typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>pb_ds;



#define IN freopen("in.txt","r",stdin)

#define OUT freopen("out.txt","w",stdout)

#define pi pair<int,int>

#define F first

#define S second

#define pb push_back

#define pp pop_back

#define mod 1000000007

#define pai acos(-1)

#define N 100005



ll Weight[N],Profit[N],dp[2][N];



int main ()

{

   ios_base::sync_with_stdio(false);

   cin.tie(NULL);

   int n,w;cin>>n>>w;

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

      cin>>Weight[i]>>Profit[i];

   }

   fill(dp[0],dp[0]+2*N,-INT_MAX*105);

   dp[(n+1)%2][0]=0;

   for(int i=n;i>=1;i--){

      for(int s=0;s<=w;s++){

         ll op1=dp[(i+1)%2][s];

         ll op2=(s-Weight[i]>=0)?Profit[i]+dp[(i+1)%2][s-Weight[i]]:0ll;

         dp[i%2][s]=max(op1,op2);

      }

   }

   ll ans=0;

   for(int i=0;i<=w;i++) ans=max(ans,dp[1][i]);

   cout<<ans<<"\n";

   return 0;

}




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

#include <vector>

#include <cmath>

#include <set>

#include <queue>

#include <map>

#include <cstdio>

#include <cstring>

#include <string>

#include <stack>

#include <algorithm>

#include <limits.h>

#include <bits/stdc++.h>

#define fw(x) freopen("x.txt","w",stdout)

#define For(i,a,b,c) for(int i = a;i < b;i+=c)

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

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

#define mem(a,s) memset(a,s,sizeof a)

#define fast ios_base::sync_with_stdio(0);cin.tie(NULL)

#define pf printf

#define sc scanf

#define ll long long

#define pii pair<int,int>

#define pll pair<ll,ll>

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

#define vii vector<int>

#define vll vector<ll>

#define vss vector<string>

#define debug(x)  cout<<#x"="<<(x)<<endl

#define pb push_back





using namespace std;





// moves



//int dx[]= {0,0,1,-1};/*4 side move*/

//int dy[]= {-1,1,0,0};/*4 side move*/

//int dx[]= {1,1,0,-1,-1,-1,0,1};/*8 side move*/

//int dy[]= {0,1,1,1,0,-1,-1,-1};/*8 side move*/

//int dx[]={1,1,2,2,-1,-1,-2,-2};/*knight move*/

//int dy[]={2,-2,1,-1,2,-2,1,-1};/*knight move*/





//big_mod



//ll bigmod(ll a,ll b,ll m)

//{if(b == 0) return 1%m;ll x = bigmod(a,b/2,m);x = (x * x) % m;if(b % 2 == 1) x = (x * a)% m;return x;}

//ll BigMod(ll B,ll P,ll M){ ll R=1%M; while(P>0) {if(P%2==1){R=(R*B)%M;}P/=2;B=(B*B)%M;} return R;} /// (B^P)%M



//ll getBit(ll num, int idx) {return ((num >> idx) & 1ll) == 1ll;}

//ll setBit1(ll num, int idx) {return num or (1ll<<idx);}

//ll setBit0(ll num, int idx) {return num & ~(1ll<<idx);}

//ll flipBit(ll num, int idx) {return num ^ (1ll<<idx);}



const int mod = 1000000007;



    int cost[101];

    int wt[101];

    ll dp[101][100001];

int main()

{

    fast;

    int n, w;

    cin>>n>>w;

    REP1(i, n) cin>>wt[i]>>cost[i];

    REP1(i, n){

      REP1(j, w){

        if(j>=wt[i]) dp[i][j] = max(dp[i-1][j], dp[i-1][j-wt[i]] + cost[i]);

        else  dp[i][j] = dp[i-1][j];

      }

    }

    cout<<dp[n][w]<<'\n';

    return 0;

}