[ABC219H] Candles

一、题目

点此看题

数轴上有 \(n\) 个蜡烛,第 \(i\) 个蜡烛的坐标是 \(x_i\),长度是 \(a_i\),每一秒蜡烛会减少 \(1\) 的长度(到 \(0\) 为止),每秒你可以移动一个单位长度,你可以把位置上的蜡烛吹熄(停止减少长度),问最后剩下的蜡烛总长度最大值。

\(n\leq 300\)

二、解法

因为我们无法记录时间,所以我们无法知道蜡烛的具体长度,但是我们知道每一秒蜡烛会减少 \(1\) 的长度,所以应用费用提前计算的思想,我们可以计算有多少个以后吹熄的蜡烛受到了这次减少的影响。

发现走的过程是一个区间,所以可以往区间 \(dp\) 方向想,每次扩展左右端点即可。因为要计算贡献我们可以额外记录还要访问的蜡烛的个数,那么每次新走到一个点时决策选不选它即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 305;
#define int long long
const int inf = 1e18;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,ans,dp[M][M][M][2];
struct node
{
	int x,y;
	bool operator < (const node &b) const
	{
		return x<b.x;
	}
}s[M];
void upd(int &x,int y) {x=max(x,y);}
signed main()
{
	n=read();
	for(int i=1;i<=n;i++)
		s[i].x=read(),s[i].y=read();
	s[++n].x=0;s[n].y=0;
	sort(s+1,s+1+n);ans=-inf;
	memset(dp,-0x3f,sizeof dp);
	for(int i=1;i<=n;i++)
	{
		
		if(s[i].x==0 && s[i].y==0)
		{
			for(int j=0;j<=n;j++)
				dp[i][i][j][0]=0;
		}
	} 
	for(int i=n;i>=1;i--)
	for(int j=i;j<=n;j++)
	for(int k=1;k<=n;k++)
	{
		upd(dp[i][j][k][0],dp[i][j][k][1]-(s[j].x-s[i].x)*k);
		upd(dp[i][j][k][1],dp[i][j][k][0]-(s[j].x-s[i].x)*k);
		int cr=(s[j+1].x-s[j].x)*k,cl=(s[i].x-s[i-1].x)*k;
		if(j<n) upd(dp[i][j+1][k-1][1],dp[i][j][k][1]-cr+s[j+1].y);
		if(j<n) upd(dp[i][j+1][k][1],dp[i][j][k][1]-cr);
		if(i>1) upd(dp[i-1][j][k-1][0],dp[i][j][k][0]-cl+s[i-1].y);
		if(i>1) upd(dp[i-1][j][k][0],dp[i][j][k][0]-cl);
	}
	for(int i=1;i<=n;i++)
	for(int j=i;j<=n;j++)
	for(int l=0;l<2;l++)
		upd(ans,dp[i][j][0][l]);
	printf("%lld\n",ans);
}
posted @ 2021-09-18 22:32  C202044zxy  阅读(301)  评论(0编辑  收藏  举报