一些神仙题
Posted zzy2005
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一些神仙题相关的知识,希望对你有一定的参考价值。
灭虫
题目链接
【问题描述】
你需要在一条无限长的道路上喷洒杀虫剂。
在这条道路上,总共有 N 个投放点,其中第 i 个投放点在数轴上坐标 pi 处。在每一
个投放点,你可以选择往左喷洒或往右喷洒。但是由于风向和地理环境的影响,向左喷洒和
向右喷洒的效果不一定相同。具体来说,在一个位置向左喷洒,可以覆盖 [pi - li, pi] 这一段
区域,而向右喷洒可以覆盖 [pi, pi + ri] 这一段区域。
请你决定每个投放点是向左喷洒还是向右喷洒,来使得被杀虫剂覆盖的路段长度和最大。
【输入】
第一行 N。
接下来 N 行,每行 pi, li, ri。
【输出】
输出最大的被杀虫剂覆盖的长度和。
Input Output
4
1 2 2
3 3 3
4 3 3
6 2 2
Output
9
样例说明
让第一个和第三个投放点向左喷洒,其他投放点向右喷洒。
这样能覆盖的区域是 [-1,8],总长度为 9。
【数据说明】
对于测试点 1、 2, N≤ 15;
对于测试点 3、 4, N≤ 3,000, ri = 0;
对于测试点 5、 6, N≤ 30;
对于测试点 7、 8, N≤ 300;
对于测试点 9、 10, N≤ 3,000;
保证 pi, li, ri ≤ 10^9。
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 3010, inf = 1e9 + 7;
int n;
struct node
int p, l, r;
bool operator < (const node &z) const
return p < z.p;
a[N];
int b[N * 3], tot, f[N][N * 3], id[N * 3];
int main()
//freopen("kill.in", "r", stdin);
//freopen("kill.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d%d", &a[i].p, &a[i].l, &a[i].r);
a[i].l = a[i].p - a[i].l; a[i].r = a[i].p + a[i].r;
b[++tot] = a[i].p; b[++tot] = a[i].l; b[++tot] = a[i].r;
sort(b + 1, b + 1 + tot); tot = unique(b + 1, b + 1 + tot) - b - 1;
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++)
a[i].p = lower_bound(b + 1, b + 1 + tot, a[i].p) - b;
a[i].l = lower_bound(b + 1, b + 1 + tot, a[i].l) - b;
a[i].r = lower_bound(b + 1, b + 1 + tot, a[i].r) - b;
id[a[i].p] = i;
//f[i][j]表示前i个区间,贡献最右点小于等于j
for (int i = 1; i <= n; i++)
for (int j = 1; j <= tot; j++) f[i][j] = f[i - 1][j];
for (int j = a[i].l + 1; j <= a[i].p; j++)
f[i][j] = max(f[i][j], f[i][j - 1] + b[j] - b[j - 1]);
//i区间贡献(k,j]
int mx = f[i - 1][a[i].p];
for (int j = a[i].p + 1; j <= a[i].r; j++)
f[i][j] = max(f[i][j], mx + b[j] - b[a[i].p]);
//i区间贡献(a[i].p,j]
if (id[j] && a[id[j]].l < a[i].p) mx = max(mx, f[i - 1][a[id[j]].l] + b[a[i].p] - b[a[id[j]].l]);
//相交
for (int j = 2; j <= tot; j++) f[i][j] = max(f[i][j], f[i][j - 1]);
printf("%d\n", f[n][tot]);
return 0;
以上是关于一些神仙题的主要内容,如果未能解决你的问题,请参考以下文章