P2120 [ZJOI2007]仓库建设(dp+斜率优化)

时间:2023-03-09 22:53:47
P2120 [ZJOI2007]仓库建设(dp+斜率优化)

思路

首先暴力DP显然,可以得20分

加上一个前缀和优化,可以得到40分

然后上斜率优化

设\(sum_i\)为\(\sum_{1}^iP_i\),\(sump_i\)为\(\sum_{1}^{i}P_i\times Pos_i\)

则决策j优于决策i的条件可以表示为

\[dp_j+C_t+pos_t \times(sum_t-sum_{j}) - (sump_t - sump_{j})<dp_i+C_t+pos_t \times(sum_t-sum_{i}) - (sump_t - sump_{i})
\]

化简即可

这里贴上我认为写的不错的一篇题解其实是懒得写式子了

dummy的题解

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
int dp[1000010],n,c[1000010],p[1000010],pos[1000010],sum[1000010],summ[1000010];
int queue[1000010],h,t;
int T(int x){
return dp[x]+summ[x];
}
int S(int x){
return sum[x];
}
signed main(){
// freopen("6.in","r",stdin);
memset(dp,0x3f,sizeof(dp));
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld %lld %lld",&pos[i],&p[i],&c[i]);
sum[i]=sum[i-1]+p[i];
summ[i]=summ[i-1]+p[i]*pos[i];
}
dp[0]=0;
// dp[1]=c[1];
for(int i=1;i<=n;i++){
while(h<t&&1.0*(T(queue[h+1])-T(queue[h]))/((S(queue[h+1])-S(queue[h])))<pos[i])
h++;
dp[i]=dp[queue[h]]+pos[i]*(sum[i]-sum[queue[h]])-(summ[i]-summ[queue[h]])+c[i];
while(h<t&&1.0*(T(i)-T(queue[t]))/((S(i)-S(queue[t])))<1.0*(T(queue[t-1])-T(queue[t]))/((S(queue[t-1])-S(queue[t]))))
t--;
queue[++t]=i;
}
printf("%lld\n",dp[n]);
return 0;
}