P4544 题解
介于本人太蠢,至死没有想出
1.O(N^2K^2)
设
考虑几个因素:
-
第
i 家商店前已经买了k 吨。 -
第
i 家商店买了p 吨。 -
上一家买的商店为
j 。
于是得到最朴素的方程:
// 75 pts
for(int i = 1; i <= N; ++ i)
for(int p = 0; p <= a[i].f; ++ p)
for(int k = 0; k + p <= K; ++ k)
for(int j = 0; j < i; ++ j)
f[i][k + p] = min(f[i][k + p], f[j][k] + sq(k) * (a[i].x - a[j].x) + a[i].c * p);
2.O(N^2K + NK^2)
我们发现在上述转移方程中,只有最后一项含有
不妨设
其中
// 90 pts
for(int i = 1; i <= N; ++ i) {
memset(g, 0x3f, sizeof g);
for(int k = 0; k <= K; ++ k) {
for(int j = 0; j < i; ++ j) {
g[k] = min(g[k], f[j][k] + sq(k) * (a[i].x - a[j].x));
}
}
for(int p = 0; p <= a[i].f; ++ p) {
for(int k = 0; k + p <= K; ++ k)
f[i][p + k] = min(f[i][p + k], g[k] + ll(p) * a[i].c);
}
}
3.O(N^2K)
把关于
这样的好处在于
// 90 pts
for(int i = 1; i <= N; ++ i) {
for(int p = 0; p <= a[i].f; ++ p) {
for(int k = 0; k + p <= K; ++ k)
f[i][p + k] = min(f[i][p + k], g[k] + sq(k) * a[i].x + ll(p) * a[i].c);
}
for(int k = 0; k <= K; ++ k) {
g[k] = min(g[k], f[i][k] - sq(k) * a[i].x);
}
}
4.O(NK\log K)
观察上述代码,复杂度瓶颈在于第一个循环。
不要枚举
for(int j = 0; j <= K; ++ j) {
for(int k = j; j - k <= a[i].f; -- k) // k \in [j - a[i].f ,j]
f[i][j] = min(f[i][j], (g[k] + sq(k) * a[i].x - (ll)k * a[i].c) + (ll)j * a[i].c);
}
也就是
后面的式子只关于
#include<bits/stdc++.h>
#define eb emplace_back
#define sq(x) (ll(x) * (x))
using namespace std;
using ll = long long;
int K, E, N;
ll f[505][10005], g[10005];
struct Node {
int x, f; ll c;
bool operator < (const Node &o) const {
return x < o.x;
}
} a[505];
ll t[400020];
#define ls x << 1
#define rs ls | 1
void init(int i, int x = 1, int l = 0, int r = K) {
if(l == r) {
t[x] = g[l] + sq(l) * a[i].x - l * a[i].c;
return;
}
int mid = l + r >> 1;
init(i, ls, l, mid), init(i, rs, mid + 1, r);
t[x] = min(t[ls], t[rs]);
}
ll query(int L, int R, int x = 1, int l = 0, int r = K) {
if(L > R) return 2e18;
if(L <= l && r <= R) return t[x];
int mid = l + r >> 1;
ll ret = 2e18;
if(L <= mid) ret = min(ret, query(L, R, ls, l, mid));
if(R > mid) ret = min(ret, query(L, R, rs, mid + 1, r));
return ret;
}
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> K >> E >> N;
for(int i = 1; i <= N; ++ i) {
cin >> a[i].x >> a[i].f >> a[i].c;
}
sort(a + 1, a + N + 1);
a[++ N].x = E;
memset(f, 0x3f, sizeof f), memset(g, 0x3f, sizeof g);
f[0][0] = 0;
g[0] = 0;
for(int i = 1; i <= N; ++ i) {
init(i);
for(int j = 0; j <= K; ++ j) {
f[i][j] =query(max(j - a[i].f, 0), j) + (ll)j * a[i].c;
}
for(int k = 0; k <= K; ++ k) {
g[k] = min(g[k], f[i][k] - sq(k) * a[i].x);
}
}
cout << f[N][K];
return 0;
}