P7302 [NOI1998] 免费的馅饼 题解

前言

  • 欸我是不是发过一遍
  • HZ26A 在学 \(DP\) 优化,于是msjing再回来学一次
  • 原题

solve

  • 这个东西让求最大,看的就很像 \(DP\)(· < · 雾
  • 我们搓一个转移方程,设 \(f_i\) 表示第 \(i\) 个必选的最大得分
$f_i = f_j + v_i$
$(2(t_i-t_j) \ge |p_i-p_j|)$
  • 我们发现柿子很简单,但是条件很复杂,我们化简一下,绝对值很烦,我们把它干掉
$ 2(t_i-t_j) \ge |p_i-p_j| = \begin{cases} 2t_i - 2t_j \ge p_i - p_j \\ 2t_i - 2t_j \ge p_j - p_i \end{cases}$
  • 我们发现从一个条件变成了两个都要成立的条件,这个柿子还是不好弄,再化简一下
\begin{cases} 2t_i - p_i \ge 2t_j - p_j \\ 2t_i + p_i \ge p_j + 2t_j \end{cases}
  • 这个就很好搞了,因为 \(i\)\(j\) 分开了
  • 我们发现这是一个二维偏序,排序干一维然后 \(DS\) 维护一维
  • \(DS\) 维护时,维护 \(\ge\) 右边的,按右边的为位置,向 \(DS\) 里加入 \(f_j\)\(DS\) 内维护最大值,查询 \(\ge\) 左边的,直接转移
  • \(DS\)\(BIT\),又好写又快
之前写的
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int w,n;
int c[maxn];
int dp[maxn];
int sum[maxn];
int ans;
struct node
{
	int t,p,v,x;
}a[maxn];
bool cmp (node nd1,node nd2){return nd1.p-2*nd1.t>=nd2.p-2*nd2.t;}
int lowbit(int x){return (x&(-x));}
void add(int w,int x)
{
	while(w<=n)
	{
		c[w]=max(c[w],x);
		w+=lowbit(w);
	}
}
int query(int w)
{
	int res=0;
	while(w)
	{
		res=max(res,c[w]);
		w-=lowbit(w);
	}
	return res;
}
int main()
{
	cin >> w >> n;
	for (int i=1;i<=n;i++)
	{
		cin >> a[i].t >> a[i].p >> a[i].v;
		sum[i]=2*a[i].t+a[i].p;
	}
	sort (sum+1,sum+1+n);
	for (int i=1;i<=n;i++)
	{
		a[i].x=lower_bound(sum+1,sum+1+n,2*a[i].t+a[i].p)-sum;
	}
	sort(a+1,a+1+n,cmp);
	for (int i=1;i<=n;i++)
	{
		dp[i]=query(a[i].x)+a[i].v;
		add(a[i].x,dp[i]);
		ans = max(ans,dp[i]);
	}
	cout << ans << endl;
	return 0;
}
posted @ 2026-07-25 11:36  msjing  阅读(7)  评论(0)    收藏  举报