#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int wi[N], vi[N];
int n, v;
/*int dp[N][N];
int main() {
cin >> n >> v;
for (int i = 1; i <= n; i++) {
cin >> vi[i] >> wi[i];
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= v; j++) {
dp[i][j]=dp[i-1][j];
if(j>=vi[i])
{
dp[i][j]=max(dp[i-1][j-vi[i]]+wi[i],dp[i][j]);
}
}
}
cout<<dp[n][v];
return 0;
}*/
/*
从二维优化到一维
全部等价删除之后
for (int i = 1; i <= n; i++) {
for (int j = vi[i]; j <= v; j++) {
dp[j]=max(dp[j-vi[i]]+wi[i],dp[j]);
//这样的话,其等价于
//dp[i][j]=max(dp[i][j],dp[i][j-vi[i])
//而非等价于
//dp[i][j]=max(dp[i][j],dp[i-1][j-vi[i])
///因为j-vi[i]是严格小于j的,当我们j是从小到大枚举的
时候,当前第i层的[j-vi[i]]其实已经被算过了,也就是说
第i-1层的[j-vi[i]]已经被第i层的 [j-vi[i]]给更新掉了。
///
而如何解决这个问题,只需要在算第i层的[j-vi[i]]的时候
dp[j-vi[i]]还是保存的第i-1层的数据即可,我们将j从大到小枚举
当枚举到j的时候,因为其严格大于j-vi[i]],而我们是从大到小枚举的
所以dp[j-vi[i]]保存的数据还未被更新到,即还是第i-1层的数据。
}
}
*/
int dp[N];
int main() {
cin >> n >> v;
for (int i = 1; i <= n; i++) {
cin >> vi[i] >> wi[i];
}
for (int i = 1; i <= n; i++) {
for (int j = v; j >= vi[i]; j--) {
dp[j] = max(dp[j - vi[i]] + wi[i], dp[j]);
}
}
cout << dp[v];
return 0;
}