传送门:洛谷 P1417
题目描述
一共有n件食材,每件食材有三个属性,
a
i
ai
ai,
b
i
bi
bi和
c
i
ci
ci,如果在t时刻完成第i样食材则得到
a
i
−
t
∗
b
i
ai-t*bi
ai−t∗bi的美味指数,用第i件食材做饭要花去
c
i
ci
ci的时间。
众所周知,gw的厨艺不怎么样,所以他需要你设计烹调方案使得美味指数最大
分析
由于
a
i
−
t
∗
b
i
ai-t*bi
ai−t∗bi这一条件的限制,看起来有些无从下手.
若是能利用某些方式摆脱
t
t
t的限制,那就好办了,直接01背包即可.
下面用相邻交换法证明一下如何排序使得前面处理的食物必定更优
假设当前已用时间为
p
p
p,有
i
i
i与
j
j
j两样食物
i
i
i先与
j
j
j的收益
w
1
=
a
i
−
(
p
+
c
i
)
×
b
i
+
a
j
−
(
p
+
c
j
+
c
i
)
×
b
j
w1 = a_i - (p + c_i) \times b_i + a_j - (p + c_j + c_i) \times b_j
w1=ai−(p+ci)×bi+aj−(p+cj+ci)×bj
j
j
j先与
i
i
i的收益
w
2
=
a
j
−
(
p
+
c
j
)
×
b
j
+
a
i
−
(
p
+
c
j
+
c
i
)
×
b
i
w2 = a_j - (p + c_j) \times b_j + a_i - (p + c_j + c_i) \times b_i
w2=aj−(p+cj)×bj+ai−(p+cj+ci)×bi
两式相减,得: $ w1 - w2 = b_i \times c_j - b_j \times c_i $
对此,若令
i
i
i在前更优,则
w
1
−
w
2
>
0
w1 - w2 > 0
w1−w2>0, 即 $ b_i \times c_j > b_j \times c_i $
因此,按照$ b_i \times c_j > b_j \times c_i 排 个 序 后 , 直 接 01 背 包 即 可 注 意 数 据 范 围 , 要 开 排个序后,直接01背包即可 注意数据范围,要开 排个序后,直接01背包即可注意数据范围,要开long$ l o n g long long
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define IL inline
using namespace std;
IL int read()
{
char c = getchar();
int sum = 0 ,k = 1;
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
return sum * k;
}
typedef long long ll;
struct node
{
ll x, y, z;
}num[55];
IL bool cmp(const node &a, const node &b)
{
return a.y * b.z > a.z * b.y;
}
IL ll max_(ll x, ll y) { return x > y ? x : y; }
ll f[100005];
int main()
{
int m = read(), n = read();
for(int i = 1; i <= n; ++i) num[i].x = read();
for(int i = 1; i <= n; ++i) num[i].y = read();
for(int i = 1; i <= n; ++i) num[i].z = read();
sort(num + 1, num + n + 1, cmp);
for(int i = 1; i <= n; ++i)
{
for(int j = m; j >= num[i].z; --j)
f[j] = max_(f[j], f[j - num[i].z] + num[i].x - num[i].y * j);
}
ll ans = 0;
for(int i = 0; i <= m; ++i)
ans = max_(ans, f[i]);
printf("%lld\n", ans);
return 0;
}