BZOJ 2131:免费的馅饼

题目大意:https://www.lydsy.com/JudgeOnline/problem.php?id=2131自己看

考虑dp

dp[i][j]为时间排序后第i个馅饼掉下在第j个位置的收益

dp[i][j]=max(dp[i][j],dp[i-1][k]+v[i]);

直接转移是n^2的,考虑优化

空间上可以只考虑排序时间后的位置,i可以去掉

然后对于那个比较RiGuai的转移条件

2*(t[i]-t[j])>=|p[i]-p[j]|  然后就可以拆一波绝对值,得到两个约束条件2t[i]+p[i]≥2t[j]+p[j]&&2t[i]−p[i]≥2t[j]−p[j]

本来这样是三维的(还有时间的限制) 但是观察一波这个约束条件,两式相加可以得到时间的约束,那么就成为了二维偏序

可以用树状数组维护前缀最大值dp转移即可

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=1e5+5;

int w,n;

struct Node {
	int v,t,p;
	int x1,x2;
}a[maxn];

bool cmp(const Node &x,const Node &y) {
	return x.x1<y.x1;
}

int tmp[maxn],f[maxn],dp[maxn],sz;

int lowbit(int x) {
	return x&(-x);
}

void modify(int pos,int val) {
	for (int i=pos;i<=sz;i+=lowbit(i)) {
		f[i]=max(f[i],val);
	}
}

int query(int pos) {
	int rt=0;
	for (int i=pos;i>=1;i-=lowbit(i)) {
		rt=max(rt,f[i]);
	}
	return rt;
}

int main() {
	scanf("%d%d",&w,&n);
	for (int i=1;i<=n;i++) {
		scanf("%d%d%d",&a[i].t,&a[i].p,&a[i].v);
		a[i].x1=2*a[i].t-a[i].p;
		a[i].x2=2*a[i].t+a[i].p;
		tmp[i]=a[i].x2;
	}
	sort(tmp+1,tmp+1+n);
	sz=unique(tmp+1,tmp+1+n)-tmp-1;
	sort(a+1,a+1+n,cmp);
	for (int i=1;i<=n;i++) {
		a[i].x2=lower_bound(tmp+1,tmp+1+sz,a[i].x2)-tmp;
	}
	int ans=0;
	for (int i=1;i<=n;i++) {
		dp[i]=max(dp[i],query(a[i].x2)+a[i].v);
		modify(a[i].x2,dp[i]);
		ans=max(ans,dp[i]);
	}
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/beloved_rancy/article/details/83023425
今日推荐