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)
(n−r+l−1−i),而当我们枚举到点
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;
}