「JSOI2010」挖宝藏

传送门

由于题目中说道挖一个位置的前提是挖掉它上面的三个,以此类推可以发现,挖掉一个点就需要挖掉这个点往上的整个倒三角,那么也就会映射到 \(x\) 轴上的一段区间(可以发现这种映射关系是一一对应的),那么我们就可以用一段区间来代表一个宝藏。

然后我们就先把所有区间按照右端点递增其次左端点递增排序。

接着考虑 \(\text{DP}\) ,我们设 \(dp_i\) 表示前 \(i\) 个区间中强制选第 \(i\) 个区间的最大利润,

那么在枚举转移点 \(j\) 时就会出现 \(i\) ,\(j\) 有交的情况,就会有一部分代价被多算。

此外还有一种情况就是一个区间完全覆盖另一个的情况,这个时候如果我们选那个较大的区间肯定会顺带选了那个较小的,

因为此时那个较小区间的代价就不用算了,所以我们可以预处理出单选一个区间的最大利润(它自己的价值以及被它覆盖的所有区间的价值之和 - 它自己的代价),

但我们又会发现,转移时会出现 \(i\) , \(j\) 两个区间同时覆盖一个小区间,导致那个小区间的价值被算重的情况,

所以我们干脆对于两个区间有交的情况我们暴力地去算可能被算重的价值即可,

具体来说就是枚举到 \(i\) 的时候,维护一个指针指向我们需要计算的区间,因为这个指针只会右移,所以我们转移的复杂度还是 \(O(n)\) 的,总复杂度也就是 \(O(n^2)\) 的。

如果有不懂的可以结合代码理解,还可以画图自己研究研究。

参考代码:

#include <algorithm>
#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
template < class T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while ('0' > c || c > '9') f |= c == '-', c = getchar();
while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
s = f ? -s : s;
} const int _ = 1002; int n, dp[_]; struct node { int l, r, p1, p2, c; } t[_];
inline bool cmp(const node& x, const node& y) { return x.r != y.r ? x.r < y.r : x.l < y.l; } inline int calc(int l, int r) { return (r - l + 2) * (r - l + 2) / 4; } int main() {
#ifndef ONLINE_JUDGE
file("cpp");
#endif
read(n);
for (rg int x, y, p, i = 1; i <= n; ++i)
read(x), read(y), read(p), t[i] = (node) { x + y + 1, x - y - 1, p, 0, calc(x + y + 1, x - y - 1) };
for (rg int i = 1; i <= n; ++i)
for (rg int j = 1; j <= n; ++j)
if (t[i].l <= t[j].l && t[j].r <= t[i].r) t[i].p2 += t[j].p1;
sort(t + 1, t + n + 1, cmp);
for (rg int i = 1; i <= n; ++i) {
dp[i] = t[i].p2 - t[i].c;
int nxt = 1, sum = 0;
for (rg int j = 1; j < i; ++j) {
if (t[j].r < t[i].l) dp[i] = max(dp[i], dp[j] + t[i].p2 - t[i].c);
if (t[j].l < t[i].l && t[i].l <= t[j].r) {
while (nxt <= i && t[nxt].r <= t[j].r) {
if (t[nxt].l >= t[i].l) sum += t[nxt].p1; ++nxt;
}
dp[i] = max(dp[i], dp[j] + t[i].p2 - t[i].c - (sum - calc(t[i].l, t[j].r)));
}
}
}
int ans = 0;
for (rg int i = 0; i <= n; ++i) ans = max(ans, dp[i]);
printf("%d\n", ans);
return 0;
}

最新文章

  1. Nhibernate的Session管理
  2. 用PowerMock mock 由工厂方法产生的对象
  3. POJ1160 Post Office[序列DP]
  4. [Solution] ASP.NET Identity(2) 空的项目使用
  5. iOS实现三屏复用循环广告[从服务器请求的广告]
  6. Sublime Text2 安装Package Control
  7. win7系统64位eclipse环境超详细暗黑1.4服务器搭建
  8. win7+ubuntu 13.04双系统安装方法
  9. DTRACE 专家
  10. 堆排序中建堆过程时间复杂度O(n)怎么来的?
  11. 遍历GridView
  12. RESTful API 最佳实践----转载阮一峰
  13. 网络爬虫re模块的findall()函数
  14. sql server2014企业版无人值守批处理脚本自动化安装
  15. NAS 百科 —— http://baike.baidu.com/item/NAS%E7%BD%91%E7%BB%9C%E5%AD%98%E5%82%A8
  16. Codeforces round 1106
  17. C# 7中函数多值返回_转自InfoQ
  18. 扫描网站服务器真实IP的小脚本
  19. markdownpad 2 pro版本 注册码
  20. C#集合之集(set)

热门文章

  1. 设置背景图片的方式(优秀)--把图片放在一个div里面
  2. 吴裕雄 python 机器学习——集成学习随机森林RandomForestRegressor回归模型
  3. Windows使用nmake和Makefile编译c++
  4. Linux中配置JDK的环境变量
  5. Mac 配置cron
  6. P &amp; R 10
  7. Python3.6打开EAIDK-610开发板(计算机通用)摄像头拍照并保存
  8. 第二次写linux驱动总结
  9. CentOS6.5_x64卸载系统原有MySQL
  10. Java开发中模拟接口工具moco的使用