正题
luogu 7302
金牌导航 数据结构优化DP-4
题目大意
在坐标轴上会出现n个金币,第i个金币tit_iti时在wiw_iwi出现(只出现一个单位时间),价值为sis_isi,当你tit_iti时在wiw_iwi,就能获得该金币,每个单位时间你最多可以移动两个单位距离,现在问你最大价值是多少
解题思路
由于坐标轴较大,所以考虑从n下手
设f_i为捡到第i个金币的最大价值,那么有:
fi=min∣wi−wj∣⩽2×(ti−tj)(fj+si)f_i=\min_{|w_i-w_j|\leqslant 2\times(t_i-t_j)}(f_j+s_i)fi=∣wi−wj∣⩽2×(ti−tj)min(fj+si)
考虑优化,先把条件拆开:
{2ti−wi⩾2tj−wj(wi⩾wj)2ti+wi⩾2tj+wj(wi<wj)\left\{\begin{matrix}2t_i- w_i\geqslant 2t_j - w_j\ \ (w_i\geqslant w_j)\\ 2t_i+ w_i\geqslant 2t_j + w_j\ \ (w_i<w_j)\end{matrix}\right.{2ti−wi⩾2tj−wj (wi⩾wj)2ti+wi⩾2tj+wj (wi<wj)
不难证明:当满足当前情况的条件时,另一情况的条件也满足,那么就是要同时满足两个条件
上式是二维偏序,可以先排序,然后用树状数组存储解决
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 100010
using namespace std;
int n, m, bn, b[N], c[N];
struct node
{int t, w, s, g1, g2;
}a[N];
void add(int x, int y)
{for (; x <= 100000; x += x&-x)c[x] = max(c[x], y);return;
}
int ask(int x)
{int g = 0;for (; x; x -= x&-x)g = max(g, c[x]);return g;
}
bool cmp(node a, node b)
{return a.g2 < b.g2;
}
int main()
{scanf("%d%d", &m, &n);for (int i = 1; i <= n; ++i){scanf("%d%d%d", &a[i].t, &a[i].w, &a[i].s);a[i].g1 = 2 * a[i].t - a[i].w;//计算两个偏序值a[i].g2 = 2 * a[i].t + a[i].w;b[i] = a[i].g1;}sort(b + 1, b + 1 + n);bn = unique(b + 1, b + 1 + n) - b - 1;for (int i = 1; i <= n; ++i)a[i].g1 = lower_bound(b + 1, b + 1 + bn, a[i].g1) - b;//离散化sort(a + 1, a + 1 + n, cmp);for (int i = 1; i <= n; ++i)add(a[i].g1, ask(a[i].g1 - 1) + a[i].s);//第二维偏序printf("%d", ask(100000));return 0;
}