P7302 [NOI1998] 免费的馅饼

(一)思路

题意不再赘述。第一眼就觉得是动态规划。

\(f(i)\)表示接到第\(i\)个馅饼能够得到的最大价值。由于一个人每次最多只能移动一格。设上一次接到的馅饼在\(p_j\),当前要接的馅饼在\(p_i\),那么,如果能同时接到馅饼\(i,j\),必要条件是:\(|p_i-p_j|\leq 2(t_i-t_j),t_i-t_j\ge0\)

因此,状态转移方程可以表示为:

\(f(i)=val(i)+\sum\limits_{|p_i-p_j|\leq 2(t_i-t_j)}f(j)\)

\(val(i)\)是第\(i\)个馅饼的价值。

因为:

\[|p_i-p_j|\leq 2(t_i-t_j)\iff \begin{cases} 2t_j-p_j\leq 2t_i-p_i \\ 2t_j+p_j\leq 2t_i-p_i\end{cases} \]

所以:

\[\displaystyle f(i)=val(i)+\sum\limits_{2t_j-p_j\leq 2t_i-p_i \wedge2t_j+p_j\leq 2t_i+p_i}f(j) \]

(二)实现

不难发现,上面的约束条件其实是一个二维偏序。因此,可以用树状数组/CDQ分治等算法和数据结构水过。由于我过于愚钝,开始没注意到二位偏序的关系,惨遭WA。

数据结构的具体做法是,先按照一维排序,然后再用数据结构维护第二维。

(三)代码

@pythoner713 巨佬强烈要求发代码。

下面是动态开点线段树的代码(因为我懒得写离散化)。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
inline int read(){
	int w = 0, f = 1; char ch = getchar();
	while(ch < '0' or ch > '9') {if(ch == '-') f = -f; ch = getchar();}
	while(ch >= '0' and ch <= '9') w = w*10 + ch - '0', ch = getchar();
	return w*f;
}
struct SegmentTree{
	int ls, rs, dat;
}t[maxn*30];
int tot;
void update(int p){
	t[p].dat = max(t[t[p].ls].dat, t[t[p].rs].dat);
}
void insert(int &p, int L, int R, int x, int val){
	if(!p) p = ++tot;
	if(L == R){
		t[p].dat = max(t[p].dat, val);
		return ;
	}
	int mid = (L+R)>>1;
	if(x <= mid) insert(t[p].ls, L, mid, x, val);
	else insert(t[p].rs, mid+1, R, x, val);
	update(p);
}
int ask(int p, int L, int R, int l, int r){
	if(!p) return 0;
	if(l <= L and r >= R){
		return t[p].dat;
	}
	int mid = (L+R)>>1, val = 0;
	if(l <= mid) val = max(val, ask(t[p].ls, L, mid, l, r));
	if(r > mid) val = max(val, ask(t[p].rs, mid+1, R, l, r));
	return val; 
}
struct PIE{
	int t, p, v;
	inline bool operator <(const PIE& x) const{
		return 2*t + p < 2*x.t + x.p;
	} 
}pie[maxn];
int N, W;
signed main(){
	tot = 1; int root = 1;
	W = read()<<1, N = read();
	for(int i=1, x, y, z; i <= N; i++){
		x = read(), y = read(), z = read(); 
		pie[i] = (PIE){x, y, z};
	}
	sort(pie+1, pie+N+1);
	for(int i=1; i<=N; i++){
		int val = ask(1, -W, W, -W, 2*pie[i].t - pie[i].p) + pie[i].v;
		insert(root, -W, W, 2*pie[i].t - pie[i].p, val);
	}
	cout<<t[1].dat<<endl;
	return 0;
}
posted @ 2021-03-31 15:58  __allenge  阅读(83)  评论(0编辑  收藏  举报