[ABC219H]Candles

Candles

题解

首先看到这道题,我们容易联想到甲虫,将不断减小的权值转化为我们 d p dp dp值的不断减少。
但这道题每个点的权值是不一样的,我们又必须保证我们选取的所有点的权值都是大于 0 0 0的,这就很难办了。这道题相当于甲虫拿到题的加强版。
但我们不妨将原题改改,改变一下两点:

  • 一个点的权值可以减小到负数。
  • 我们可以选择一些点不要,即这部分点不参加计算。

很明显,在我们的最优选择情况下,我们一定会让那些权值会减小到负数的点不参与 d p dp dp计算,因为这样的答案是更优的,故这样我们就不需要考虑还有哪些点会减少了,在减少的点都是会被选的点。

于是,很容易就可以定义出 d p dp dp状态。
d p l , r , i , 0 / 1 dp_{l,r,i,0/1} dpl,r,i,0/1表示我们已经覆盖了区间 [ l , r ] [l,r] [l,r],区间 [ l , r ] [l,r] [l,r]外有 i i i个点是被删除掉的,我们现在在左/右边界。
转移就很好想了,就是从那个端点向哪边扩散与当前加入的点是不是被删除的。
没走一步会使得我们的总贡献减少 ( n − r + l − 1 − i ) (n-r+l-1-i) (nr+l1i),而当我们枚举到点 i i i不选时同样会让我们的答案减少 a i a_{i} ai
跑一遍区间 d p dp dp即可,最后的答案即为 max ⁡ ( d p 1 , n , 0 , 0 , d p 1 , n , 0 , 1 ) \max(dp_{1,n,0,0},dp_{1,n,0,1}) max(dp1,n,0,0,dp1,n,0,1)

时间复杂度 O ( n 3 ) O\left(n^3\right) O(n3)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;       
const LL INF=0x3f3f3f3f3f3f3f3f;   
const int mo=1e9+7;
const int inv2=499122177;
const int jzm=2333;
const int lim=1e9;
const int n1=400;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n;LL dp[305][305][305][2],summ;
struct ming{int x,a;}s[305];
bool cmp(ming x,ming y){return x.x<y.x;} 
signed main(){
	read(n);for(int i=1;i<=n;i++)read(s[i].x),read(s[i].a),summ+=s[i].a;
	s[++n]=(ming){0,0};sort(s+1,s+n+1,cmp);int st=0;
	for(int i=1;i<=n;i++)if(s[i].x==0)st=i;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			for(int k=1;k<=n;k++)
				dp[i][j][k][0]=dp[i][j][k][1]=-INF;
	for(int i=0;i<n;i++)dp[st][st][i][0]=dp[st][st][i][1]=summ;
	for(int len=1;len<n;len++)
		for(int l=1,r=len;r<=n;l++,r++){
			if(l>st||r<st)continue;
			LL tmp1=s[r].x-s[l-1].x,tmp2=s[r+1].x-s[l].x;
			LL tmp3=s[l].x-s[l-1].x,tmp4=s[r+1].x-s[r].x;
			for(int i=0;i<=n-len;i++){
				LL t=n-i-len;
				if(l>1)dp[l-1][r][i][0]=max(dp[l][r][i][1]-t*tmp1,dp[l-1][r][i][0]);
				if(l>1&&i)dp[l-1][r][i-1][0]=max(dp[l][r][i][1]-t*tmp1-s[l-1].a,dp[l-1][r][i-1][0]);
				if(l>1)dp[l-1][r][i][0]=max(dp[l][r][i][0]-t*tmp3,dp[l-1][r][i][0]);
				if(l>1&&i)dp[l-1][r][i-1][0]=max(dp[l][r][i][0]-t*tmp3-s[l-1].a,dp[l-1][r][i-1][0]);
				if(r<n)dp[l][r+1][i][1]=max(dp[l][r][i][0]-t*tmp2,dp[l][r+1][i][1]);
				if(r<n&&i)dp[l][r+1][i-1][1]=max(dp[l][r][i][0]-t*tmp2-s[r+1].a,dp[l][r+1][i-1][1]);
				if(r<n)dp[l][r+1][i][1]=max(dp[l][r][i][1]-t*tmp4,dp[l][r+1][i][1]);
				if(r<n&&i)dp[l][r+1][i-1][1]=max(dp[l][r][i][1]-t*tmp4-s[r+1].a,dp[l][r+1][i-1][1]);
			}
		}
	printf("%lld\n",max(dp[1][n][0][0],dp[1][n][0][1]));
	return 0;
}

谢谢!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值