题解 P7318 【[JSOI2010] 挖宝藏】
容易发现挖掉某一个宝藏需要挖掉其上方整个倒三角内的所有方块,我们假设这个倒三角在
对于一个宝藏,我们可以在
之后是一个比较套路的 dp,设
- 若
j 区间与i 区间无交,直接加上j 的利润; - 若
j 区间被i 区间完全包含,贡献已经预处理,直接跳过; - 若
j 区间与i 区间有交,因为交的代价被减了两次,加上j 的利润后再加上交的部分的代价;
然后你会发现这个 dp 是有问题的,考虑一种情况,假设对于
如果每次 dp 都暴力去找这些区间的话时间复杂度是
#include <map>
#include <ctime>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int x = 0, w = 1;char ch = getchar();
while (ch > '9' || ch < '0') { if (ch == '-')w = -1;ch = getchar(); }
while (ch >= '0' && ch <= '9')x = x * 10 + ch - '0', ch = getchar();
return x * w;
}
inline void write(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
const int maxn = 1e3 + 5;
const int mod = 1e9 + 7;
const int inf = 1e9;
inline int min(int x, int y) { return x < y ? x : y; }
inline int max(int x, int y) { return x > y ? x : y; }
struct node {
int l, r, v1, v2, w;
bool operator < (const node p) const {
return r == p.r ? l < p.l : r < p.r;
}
} a[maxn];
int n, ans, cnt, pos, f[maxn];
inline int calc(int l, int r) {
int delta = (l + r) & 1;
return (r - l + 2 + delta) * (r - l + 2 - delta) / 4;
}
int main() {
n = read();
for (int i = 1, x, y; i <= n; i++) {
x = read(), y = read();
a[i].l = x + y + 1, a[i].r = x - y - 1;
a[i].v1 = read(), a[i].w = calc(a[i].l, a[i].r);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (a[i].l <= a[j].l && a[j].r <= a[i].r)
a[i].v2 += a[j].v1;
sort(a + 1, a + n + 1);
for (int i = 1, val;i <= n;i++) {
f[i] = val = a[i].v2 - a[i].w, pos = 1, cnt = 0;
for (int j = 1, tmp; j < i; j++) {
if (a[j].r >= a[i].l && a[j].l < a[i].l) {
while (pos <= i && a[pos].r <= a[j].r) {
if (a[pos].l >= a[i].l) cnt += a[pos].v1;
pos++;
}
tmp = calc(a[i].l, a[j].r);
f[i] = max(f[i], f[j] + val + tmp - cnt);
}
else if (a[j].r < a[i].l) f[i] = max(f[i], f[j] + val);
}
}
for (int i = 0;i <= n;i++) ans = max(f[i], ans);
printf("%d\n", ans);
return 0;
}