题目链接:
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 n, m, c0 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 ai, bi, ci 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;
}