Hoping for the best but expecti|

EricQian06

园龄:4年6个月粉丝:24关注:43

2022-08-14 17:45阅读: 27评论: 0推荐: 0

CF559E Gerald and Path(DP)

CF559E Gerald and Path

dp(i,p) 表示完成前 i 条线段的覆盖,最右端位于 p 点的最大收益。

转移?向下一条线段转移时加上他们中间的距离?发现这样没有办法统计 p 点以前的空位了!

Trick:如果出现上面没有办法统计 p 点以前的空位的情况,说明覆盖 p 点的这条线段是没有用的,每次只需要考虑有用的线段

若要枚举有用的线段,从 i 点枚举下一个有用的线段 k,钦定 [i+1,k1] 之间的线段都是没有用的,这样就可以像上面一样转移了。

但是,如果没有用的线段中出现一个线段它的右端点超过了 k 线段的右端点呢?那就再扫过 [i+1,k1] 线段的时候统计下最右边端,再加上它与 k 线段右端的贡献即可。

实现的时候记 p 点只用记录最右端线段编号和朝向即可,设 dp(i,j,p) 表示到 i 线段为止,最右边的线段是 j,它的朝向为 p 的最大收益。

dp(k,x,y)dp(i,j,p)+min(rkp,lenk)+rxrk

#define Maxn 105
int n,ans;
int dp[Maxn][Maxn][2];
struct Seg
{
	int pos,len;
	Seg(int Pos=0,int Len=0):pos(Pos),len(Len){}
	inline bool friend operator < (Seg x,Seg y) { return x.pos<y.pos; }
}s[Maxn];
int main()
{
	n=rd();
	for(int i=1,p,l;i<=n;i++) p=rd(),l=rd(),s[i]=Seg(p,l);
	sort(s+1,s+n+1),s[0].pos=-inf;
	for(int i=0;i<=n;i++)
		for(int j=0;j<=i;j++) for(int p=0;p<2;p++)
		{
			int rn=s[j].pos+p*s[j].len,maxx=-inf,pos=-1,d;
			ans=max(ans,dp[i][j][p]);
			for(int k=i+1;k<=n;k++) for(int q=0;q<2;q++)
			{
				int cur=s[k].pos+q*s[k].len;
				if(cur>=maxx) maxx=cur,pos=k,d=q;
				dp[k][pos][d]=max(dp[k][pos][d],
					dp[i][j][p]+min(cur-rn,s[k].len)+maxx-cur);
			}
		}
	printf("%d\n",ans);
	return 0;
}

本文作者:EricQian's Blog

本文链接:https://www.cnblogs.com/EricQian/p/16585902.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   EricQian06  阅读(27)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起