# -*- coding:utf-8 -*-
""" AcWing-5 多重背包问题_II
[题目]:
        有 N 件物品和一个容量是 V 的背包。
        第 i 种物品最多有 si 件，每件体积是 vi，价值是 wi。

        求解将哪些物品装入背包，可使这些物品的总体积不超过背包容量，且总价值最大。
        输出最大价值。

[输入格式]: 第一行两个整数，N，V，用空格隔开，分别表示物品数量和背包容积。
            接下来有 N 行，每行两个整数 vi,wi，用空格隔开，分别表示第 i 件物品的体积和价值。
[输出格式]: 输出一个整数，表示最大价值。

[数据范围]:
         0 < N ≤ 1000
         0 < V ≤ 2000
         0 < vi, wi, si ≤ 2000

[输入样例]:
            4 5
            1 2 3
            2 4 1
            3 4 3
            4 5 2
[输出样例]：
            10
"""

# [思路]：我们模拟装包过程得到下面的状态转移方程
#
# dp[i][j] = max({dp[i-1][j-k*vi]+k*wi: 0 <= k <= si})
# 根据方程迭代的过程，我们可以计算出时间复杂度为 O(N*V*sum_{i}si)
# 在 AcWing-4问题中，我们通过直接循环嵌套的代码处理了当数据范围较小的情况。
# 当前的问题，数据的范围变大了，那么之前的处理方法会超时。
#
# 这里我们考虑利用二进制分组的办法，将时间复杂度降低为 O(N*V*sum_{i}log(s_i))
# 主要的思路，我们可以通过分苹果的例子来类比。
# 比如说，现在要取n个苹果，那么直接的方法就是一个一个拿，那么需要取n次。
# 但如果我们将已有的苹果按照二进制分组(2^0, 2^1, 2^2, 2^3, 2^4, ..., 2^k, ...)
#
# 如果我们要取1000个苹果，那么只需要对现有的苹果分为10个箱子，
# 每个箱子里的苹果数就是二进制的对应的数(2^0, 2^1, 2^2, 2^3, 2^4, ..., 2^9)，由于2^10 = 1024
# 所以我们此时最多取10次箱子就可以了，按照这个想法，当需要拿取的苹果数越多时，相比之前的方法，二进制的办法能够降低运算复杂度。
#
# 因此，我们将类似的想法应用到这个问题上，那么对于上面的状态转移方程
# 在每一轮状态 dp[i - 1][j - k*vi] + k*wi, (0 <= k <= si) 进行对比取最大的过程之前，我们可以先对si进行二进制分组
# 假设 mi = max({t: 2^t <= si, t>=0})，那么对si进行分组 (2^0, 2^1, 2^2, ..., 2^mi, si-2^0-2^1-...-2^mi)
#
# 那么取当前第i种物品，背包中增加的重量为下面二进制分组后列表中的一个
#     [2^0 * goods[i][0], 2^1 * goods[i][0], 2^2 * goods[i][0], ..., 2^mi * goods[i][0], (si-2^0-2^1-...-2^mi) * goods[i][0]]
# 同样地，那么取当前第i种物品，获得的价值也是下面二进制分组后列表中的一个
#     [2^0 * goods[i][1], 2^1 * goods[i][1], 2^2 * goods[i][1], ..., 2^mi * goods[i][1], (si-2^0-2^1-...-2^mi) * goods[i][1]]
# 其中 i = 0, 1, ..., N-1
#
# 也就是说，我们将原问题中每种物品最多选取固定个数，来计算最大价值的问题，
# 通过二进制分组转化为从上面两个列表中选择或者不选择能获得最大价值的01背包问题。
# 参考：https://www.acwing.com/solution/content/20115/

class Solution_1:
    def fun(self, N, V, goods):
        v = []  # 存储分组后各物品的重量
        w = []  # 存储分组后各物品的价值
        cnt = 0  # 分组的组别
        for i in range(N):
            k = 1  # 用于每一轮对各物品的重量和价值进行二进制分组更新存放
            s = goods[i][2]  # 当前重量为goods[i][0]的物品，价值为goods[i][1]，并且有goods[i][2]个

            # 下面whlie循环和if判断中的代码是对s进行二进制分组处理
            while k <= s:
                v.append(k * goods[i][0])
                w.append(k * goods[i][1])
                s -= k  # s 每轮减小
                k *= 2  # 组别里面的个数增加
                cnt += 1  # 每一轮划分完组别后，更新组别数

            # 若s余下的数不能表示成2的幂次，那么就单独作为一个组别
            # 比如，若s=10，那么分组为(2^0*X, 2^1*X, 2^2*X, (s - 2^0 - 2^1 - 2^2)*X) = (1*X, 2*X, 4*X, 3*X)
            # 其中X表示各物品的重量(goods[i][0])或者价值(goods[i][1])
            if s > 0:
                v.append(s * goods[i][0])
                w.append(s * goods[i][1])
                cnt += 1  # 更新组别数

        n = cnt  # 枚举次数由输入的个数转化为组别数

        # 接下来转化为01背包问题处理，这里直接写成优化后的一维数组形式
        dp = [0 for _ in range(V + 1)]
        for i in range(n):
            for j in range(V, v[i] - 1, -1):
                dp[j] = max(dp[j], dp[j - v[i]] + w[i])
        return dp[-1]





if __name__ == '__main__':
    while True:
        try:
            N, V = list(map(int, input().split()))
            goods = []  # 存放(vi, wi, si)
            for i in range(N):
                goods.append(list(map(int, input().split())))
            print(Solution_1().fun(N, V, goods))
        except:
            break


