[CF106C]Buns -多重背包

题目链接:

http://codeforces.com/problemset/problem/106/C

C. Buns

Lavrenty, a baker, is going to make several buns with stuffings and sell them.

Lavrenty has n grams of dough as well as m different stuffing types. The stuffing types are numerated from 1 to m. Lavrenty knows that he has ai grams left of the i-th stuffing. It takes exactly bi grams of stuffing i and ci grams of dough to cook a bun with the i-th stuffing. Such bun can be sold for di tugriks.

Also he can make buns without stuffings. Each of such buns requires c0 grams of dough and it can be sold for d0 tugriks. So Lavrenty can cook any number of buns with different stuffings or without it unless he runs out of dough and the stuffings. Lavrenty throws away all excess material left after baking.

Find the maximum number of tugriks Lavrenty can earn.

Input

The first line contains 4 integers nmc0 and d0 (1 ≤ n ≤ 1000, 1 ≤ m ≤ 10, 1 ≤ c0, d0 ≤ 100). Each of the following m lines contains 4integers. The i-th line contains numbers aibici and di (1 ≤ ai, bi, ci, di ≤ 100).

Output

Print the only number — the maximum number of tugriks Lavrenty can earn.

Examples

input

10 2 2 1
7 3 2 100
12 3 1 10

output

241

input

100 1 25 50
15 5 20 10

output

200

Note

To get the maximum number of tugriks in the first sample, you need to cook 2 buns with stuffing 1, 4 buns with stuffing 2 and a bun without any stuffing.

In the second sample Lavrenty should cook 4 buns without stuffings.

题目大意:

面包师Lavrenty打算用馅料做几个面包,然后把它们卖掉。

Lavrenty有\(n\)克面团和\(m\)种不同的馅料。馅料种类的下标从\(1到m\),他知道他的第\(i\)种馅料剩下\(a_i\) 克,做一个第\(i\)种馅料的面包,恰恰需要\(b_i\)克的\(i\)种馅料和\(c_i\)克的面团,同时这种面包可以卖\(d_i\)块钱。

他也可以做没有馅的面包。每个这样的面包需要\(c_0\)克面团,可以卖\(d_0\)块Tugrik。所以Lavrenty可以做任何数量的包子,用不同的馅料或者不用馅料,除非用完了面团和馅料。Lavrenty会扔掉烘培面包后剩下的所有多余材料。

求出Lavrenty可以赚取的钱的最大数量。

输入格式

第一行4个整数n,m,\(c_0,d_0\) \(1<=n<=1000,1<=m<=10\)
接下来m行每行四个整数\(a_i,b_i,c_i,d_i\) \(1<=a_i,b_i,c_i,d_i<=100\)

输出格式

输出Lavrenty可以赚取的最大钱数

思路:

多重背包+二进制优化(对多重中的二进制优化)

This is the code

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<sstream>
#include<stack>
#include<string>
#include<set>
#include<vector>
using namespace std;
#define PI acos(-1.0)
#define EPS 1e-8
#define MOD 1e9+7
#define LL long long
#define ULL unsigned long long     //1844674407370955161
#define INT_INF 0x7f7f7f7f      //2139062143
#define LL_INF 0x7f7f7f7f7f7f7f7f //9187201950435737471
// ios::sync_with_stdio(false);
// 那么cin, 就不能跟C的 scanf,sscanf, getchar, fgets之类的一起使用了。;
const int dr[]= {0, -1, 1,0, -1, -1, 1, 1};
const int dc[]= { 1, 0, 0, -1,-1, 1, -1, 1};
const int N = 100005;
int a[N];//表示第i种馅料剩余数量
int b[N];//表示做一个第i种馅饼需要的馅料数量
int c[N];//表示做一个第i种馅饼需要的面团数量
int d[N];//表示做一个第i种馅饼的收益
int num[N];//表示馅能够做几个,优化
int dp[N];
//0-1背包过程(减)
void ZERO_ONE_PACK(int cost,int m,int w) //m一般为容量或限制条件
{
    for(int i=m; i>=cost; i--)
        dp[i]=max(dp[i], dp[i-cost]+w);
}
//完全背包过程(加)
void COMPLETE_PACK(int cost,int m,int w) //m一般为容量或限制条件
{
    for(int i=cost; i<=m; i++)
        dp[i]=max(dp[i],dp[i-cost]+w);
}
void MULTIPLY_PACK(int cost,int m,int num,int w) //m一般为背包容量和限制条件
{
    //花费足够
    //这道题目就是馅料的数量足够
    if(cost*num>=m)
    {
        COMPLETE_PACK(cost,m,w);
        return ;
    }
    //馅料的不够
    //二进制优化
    int k=1;
    while(k<num)
    {
        ZERO_ONE_PACK(cost*k,m,k*w);
        num-=k;
        k*=2;
    }
    ZERO_ONE_PACK(cost*num,m,num*w);
}
int main()
{
    /*
    n 面团的千克
    m 馅料的种类
    */
    int n,m,c0,d0;
    while(~scanf("%d%d%d%d",&n,&m,&c0,&d0))
    {
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
            num[i]=a[i]/b[i];//表示馅能够做几个
        }
        for(int i=1; i<=n; i++)
            dp[i]=i/c0*d0;//dp初始化的是i克面团不使用馅料,所能够卖的钱数
        for(int i=1; i<=m; i++)
            MULTIPLY_PACK(c[i],n,num[i],d[i]);//对每一种馅料进行求
        printf("%d\n",dp[n]);
    }
    return 0;
}

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值