#include <iostream>
#include<vector>
//#include<cmath>
using namespace std;

int main()
{
    //是传统的01背包问题的变形,只用处理主件,在处理每一个主件时,都要分四种情况来考虑,分别是只有主件,主件和附件一,主件和附件二,主件和附件一二,附件不用单独考虑。类似于分组背包问题,把附件和主件作为一个组,每个组中有最多四个情况进行四选一操作
    //创建物品类
    class item {
    public:
        int v;//价格
        int m;//满意度
        int q;//主件编号
    };
    int n, m;//预算和物品总数
    cin >> n >> m;
    vector<vector<item>>group(m);//分组存储item
    int count = 0;//主件的个数
    for (int i = 0; i < m; i++)//循环存放m个物品到group中
    {
        item tmp;
        int w = 0;
        cin >> tmp.v >> w >> tmp.q;
        if (tmp.q == 0)
            count++;
        tmp.m = tmp.v * w;
        group[i].push_back(tmp);
    }
    //将每一个附件和其对应的主件组成一个分组
    for (auto it : group)
    {
        if (it[0].q == 0)//主件不处理
            continue;
        else//附件则找对应主件进行组合
        {
            int index = it[0].q;//对应的主件编号
            //主件和附件组合
            int size = group[index - 1].size(); // 当前主件的组合数
            for (int k = 0; k < size; k++)
            {
                item fix;
                fix.q = group[index - 1][k].q;
                fix.v = group[index - 1][k].v +it[0].v;
                fix.m = group[index - 1][k].m + it[0].m;
                group[index - 1].push_back(fix);
            }
        }
    }
	//一维数组实现,dp[j]表示当前预算为j时的最大价值
	vector<int> dp(n + 1, 0);
    for (int i = 0; i < m; i++)
    {
        if (group[i][0].q != 0)
            continue;//不处理只有附件的组
        for(int j = n; j>=group[i][0].v ; j--)//逆向遍历数组防止重复选择物品
            for (auto it : group[i])//依次判断组中的每种情况
            {
                if (j >= it.v)
                {
                    dp[j] = max(dp[j], dp[j - it.v] + it.m);
                }
            }
    }
    cout << dp[n];
}