现在的位置: 首页 > 综合 > 正文

ZOJ3381

2019年08月20日 ⁄ 综合 ⁄ 共 1006字 ⁄ 字号 评论关闭

DP+线段树,

dp[i]记录从i开始的最大收益,

dp[i]=s[i]+max(dp[x]|i+x[i]<=x<i+y[i]);

利用线段树维护个最大值就行了

#include<cstdio>
#define MAXN 50010
#define max(a,b) ((a)>(b))?(a):(b)
int n,s[MAXN],x[MAXN],y[MAXN];
int seg[4*MAXN];
int dp[MAXN];
void up(int x)
{
	seg[x]=max(seg[2*x],seg[2*x+1]);
}
void build(int l,int r,int i)
{
	seg[i]=0;
	if(l==r)
		return;
	int m=(l+r)>>1;
	build(l,m,2*i);
	build(m+1,r,2*i+1);
}
void ud(int l,int r,int pos,int i,int x)
{
	if(l==r&&l==pos)
	{
		seg[i]=x;
		return;
	}
	int mid=(l+r)>>1;
	if(mid>=pos)
		ud(l,mid,pos,2*i,x);
	else
		ud(mid+1,r,pos,2*i+1,x);
	up(i);
}
int qu(int l,int r,int a,int b,int i)
{
	if(l==a&&r==b)
		return seg[i];
	int mid=(l+r)>>1;
	if(mid>=b)
		return qu(l,mid,a,b,2*i);
	else
		if(a>mid)
			return qu(mid+1,r,a,b,2*i+1);
		else
			return max(qu(l,mid,a,mid,2*i),qu(mid+1,r,mid+1,b,2*i+1));
}
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		build(1,n,1);
		for(int i=1;i<=n;i++)
			scanf("%d%d%d",s+i,x+i,y+i);
		dp[n]=s[n];
		for(int i=n-1;i>=1;i--)
		{
			ud(1,n,i+1,1,dp[i+1]);
			if(i+y[i]-1<=n)
			dp[i]=s[i]+qu(1,n,i+x[i],i+y[i]-1,1);
			else
			if(i+x[i]<=n)
			dp[i]=s[i]+qu(1,n,i+x[i],n,1);
			else
			dp[i]=s[i];
		}
		printf("%d\n",dp[1]);
	}
	return 0;
}
【上篇】
【下篇】

抱歉!评论已关闭.