ABC219H 题解
ABC219H 题解
ABC219H Candles
题意
坐标轴上放着
每过
当高桥到达一个蜡烛的时候,他可以把蜡烛吹灭;此时蜡烛不会继续燃烧,不会减少长度了。
问:最后蜡烛能剩下的最长长度是多少?
题目分析
Part 1
P1220 关路灯
注意到本题的限制:蜡烛的长度不会减到负数。这是和 P1220 唯一的区别。
考虑一个简单的版本:蜡烛可以烧到负数。这题就变成了 P1220。
dp 初始值为所有蜡烛长度的和,然后直接做就好了。
这里,我们不需要知道这个蜡烛到底有没有真正烧完。那么答案一定是所有蜡烛都正常熄灭的情况。
此时所有合法的状态都被合法地统计到了。而不合法的情况,都没有合法情况来的好:烧到负数的蜡烛,还不如直接自己灭掉;没烧到负数的蜡烛我们当成了负数,长度取了
总状态数
于是乎,这个题就做完了。
认为难理解的(点名批评我自己),这里可以画个图感受一下整个过程。
note:
- 注意要对下标排序。
- 对于原点,可以另开一个下标为
0 ,长度为0 的蜡烛。(虽然我的代码里没有())(orz hellojim \se)
code
整个代码就上面那两个方程的实现。式子稍微有点长,耐着性子自己推一推,誊到代码里就好了。
#include<bits/stdc++.h>
#define ll long long
#define ld long double
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define REP(i,j) for(int i=0;i<j;++i)
#define REPA(i,j) for(int i=1;i<=j;++i)
#define vi vector<int>
#define pii pair<int,int>
#define all(a) a.begin(),a.end()
using namespace std;
const int MAXN=330;
int N;
pair<ll,ll>A[MAXN];
ll dp[MAXN][MAXN][MAXN][2];
ll S=0;
int main(void){
scanf("%d",&N);
REP(i,N)scanf("%lld%lld",&A[i].fi,&A[i].se),S+=A[i].se;
sort(A,A+N);
int it=0;
while(it<N&&A[it].fi<0)++it;
if(it<N)REP(i,N)dp[it][it][i][0]=dp[it][it][i][1]=max(S-A[it].fi*(N-i),S-A[it].fi*(N-i-1)-A[it].se);
--it;
if(it>=0)REP(i,N)dp[it][it][i][0]=dp[it][it][i][1]=max(S+A[it].fi*(N-i),S+A[it].fi*(N-i-1)-A[it].se);
for(int len=2;len<=N;++len){
for(int l=0,r=len-1;r<N;++l,++r){
for(int k=0;k<=N-len;++k){
dp[l][r][k][0]=max(
max(dp[l+1][r][k][0]-(A[l+1].fi-A[l].fi)*(N-len-k+1),dp[l+1][r][k+1][0]-(A[l+1].fi-A[l].fi)*(N-len-k)-A[l].se),
max(dp[l+1][r][k][1]-(A[r].fi-A[l].fi)*(N-len-k+1),dp[l+1][r][k+1][1]-(A[r].fi-A[l].fi)*(N-len-k)-A[l].se)
);
dp[l][r][k][1]=max(
max(dp[l][r-1][k][1]-(A[r].fi-A[r-1].fi)*(N-len-k+1),dp[l][r-1][k+1][1]-(A[r].fi-A[r-1].fi)*(N-len-k)-A[r].se),
max(dp[l][r-1][k][0]-(A[r].fi-A[l].fi)*(N-len-k+1),dp[l][r-1][k+1][0]-(A[r].fi-A[l].fi)*(N-len-k)-A[r].se)
);
}
}
}
ll ans=max(dp[0][N-1][0][0],dp[0][N-1][0][1]);
printf("%lld",ans);
return 0;
}