#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];
}