#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20010; // todo 待分析
int n, m;
int f[N], g[N], q[N];
// 思考使用单调队列来做
// f[i,j]: 所有考虑前i个物品,总数量为j的集合的最大值
// f[i,j] = max(f[i-1,j], f[i-1,j-v]+w, f[i-1,j-2v]+2w, f[i-1,j-3v]+3w,..., f[i-1,j-kv]+kw)
// f[i,j-v] = max(f[i-1,j-v], f[i-1,j-2v]+w, f[i-1,j-3v]+2w,..., f[i-1,j-kv]+(k-1)w, f[i-1,j-(k+1)v]+kw)
// f[i,j-2v] = max(f[i-1,j-2v], f[i-1,j-3v]+w, ..., f[i-1,j-kv]+(k-2)w, f[i-1,j-(k+1)v]+(k-1)w, f[i-1,j-(k+2)v]+kw)
// 滑动窗口,每个考虑k个取值
// 构建窗口所需要的数标
int main() {
cin >> n >> m;
for (int i = 0; i < n; i ++) {
int v, w, s;
cin >> v >> w >> s;
memcpy(g, f, sizeof f); // 每一轮重新来过
for (int j = 0; j < v; j ++) { // 这里循环?, f[0-v]都进行更新吧,因为体积,所以0~v, ?1~v
int hh = 0, tt = -1;
for (int k = j; k <= m; k += v) {
// 注意两点:1. 这里存的是索引 2. 实际上操作的是 (r, w), (r+v, -w); 不过这里r是从0到v-1进行枚举的
if (hh <= tt && q[hh] < k - s * v) hh ++;
if (hh <= tt) f[k] = max(f[k], g[q[hh]] + (k - q[hh]) / v * w);
// g[q[hh]]即f[i-1, j- max * v]
// (k-q[hh)/v 即 kw中的k
while (hh <= tt && g[q[tt]] - (q[tt] - j) / v * w <= g[k] - (k - j) / v * w) tt --;
// 小于等于,队首存储的是最大值
q[ ++ tt] = k;
}
}
}
cout << f[m] << endl;
return 0;
// todo 时空复杂度分析 时间复杂度 n*v*(v/k)? 空间O(n)
// 二进制优化版本 n*v*(logS)
}