Luogu P4544 [USACO10NOV]Buying Feed G
rsdbk_husky · · 题解
放在前面:本方法时间复杂度为
零. 安利:
安利一下我的博客。
一. 变量声明:
二. 思路
1. 思考解法
- 路线上后面的商店不会影响路线前半部分的最优解,符合无后效性。
- 有最大容量
W ,有可选择的物品,每个物品有重量和价值,明显是背包类问题。
所以考虑背包 DP。
2. 初始状态
3. 结束状态
5. 单调队列优化(重点)
枚举
重点一 :观察上面这个拆了个括号的方程,左边是我们要去求的状态,在该状态下,for 循环枚举出来的,所以我们当然知道他的值)。所以我们可以将
重点二:这个方程中的变量只有
三. 代码
#include<bits/stdc++.h>
using namespace std;
#define re register
#define int long long
const int MAXn = 500;
const int MAXW = 10000;
template <class T>
inline void read(T &a) {
register char c;while (c = getchar(), c < '0' || c >'9');register T x(c - '0');while (c = getchar(), c >= '0' && c <= '9')x = (x << 1) + (x << 3) + c - '0';a = x;
}
template <class T>
inline T min(T a, T b) {
return a < b ? a : b;
}
struct Shop {
int x;
int w;
int v;
Shop(): x(0), w(0), v(0){}
Shop(int x_, int w_, int v_): x(x_), w(w_), v(v_) {}
inline bool operator < (Shop &a) {
return this->x < a.x;
}
};
Shop shop[MAXn + 10];
int W, n, d[MAXn + 10][MAXW + 10];
int head, tail, que[MAXW + 10];
inline int calc(int i, int k) {
return d[i - 1][k] + (shop[i].x - shop[i - 1].x) * k * k - shop[i].v * k;
}
signed main() {
int E;
read(W), read(E), read(n);
shop[0] = Shop(0, 0, 0); //本人将起点和终点(家)时当做食物数为 0 的商店,这样能避免特判,所以“home”就是n+1
for (re int i = 1, x, w, v; i <= n; ++i) {
read(x), read(w), read(v);
shop[i] = Shop(x, w, v);
}
shop[n + 1] = Shop(E, 0, 0); //同上
sort(shop, shop + n + 2);
memset(d, 0x3f, sizeof(d));
d[0][0] = 0;
for (re int i = 1; i <= n + 1; ++i) { //i:当前阶段是在哪个店
head = 1; tail = 0;
for (re int j = 0; j <= W; ++j) { //j:当前状态要求在此处商店购买后车上有多少饲料
while (calc(i, que[tail]) > calc(i, j) && head <= tail)
--tail;
if (j - que[head] > shop[i].w && head <= tail)
++head;
que[++tail] = j;
d[i][j] = calc(i, que[head]) + shop[i].v * j;
}
}
printf("%lld", d[n + 1][W]);
}