bzoj 1911 [Apio2010]特别行动队
Posted huangchenyan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1911 [Apio2010]特别行动队相关的知识,希望对你有一定的参考价值。
DP+斜率优化
dp[i]表示在前第i个士兵在特别行动队中最后一个时战斗力的最大值
sum[i]表示战斗力的前缀和
答案一定是dp[n]
dp[i]=dp[j]+a*(sum[i]-sum[j])^2+b*(sum[i]-sum[j])+c
令j优于k,则得到
2*a*sum[i]*(sum[k]-sum[j])>dp[k]+a*sum[k]^2-b*sum[k]-(dp[j]+a*sum[j]^2-b*sum[j])
令f[x]=dp[x]+a*sum[x]^2-b*sum[x]
2*a*sum[i]*(sum[k]-sum[j])>f[k]-f[j]
2*a*sum[i]>(f[k]-f[j])/(sum[k]-sum[j])
用单调队列维护即可
#include <bits/stdc++.h> #define ll long long using namespace std; const ll MAXN=1e6+100; ll n,a,b,c,sum[MAXN],dp[MAXN]; ll l,r,q[MAXN]; ll f(ll x) { return dp[x]+a*sum[x]*sum[x]-b*sum[x];//如上 } double xie(ll x,ll y) { return ((double)f(x)-f(y))/((double)sum[x]-sum[y]);//求斜率 } int main() { scanf("%lld",&n); scanf("%lld%lld%lld",&a,&b,&c); for (ll i=1;i<=n;i++) { ll num; scanf("%lld",&num); sum[i]=sum[i-1]+num; }for (ll i=1;i<=n;i++) { while (l<r && xie(q[l],q[l+1])>(double)2*a*sum[i])//维护单调队列 l++; dp[i]=dp[q[l]]+a*(sum[i]-sum[q[l]])*(sum[i]-sum[q[l]])+b*(sum[i]-sum[q[l]])+c; while (l<r && xie(q[r],i)>xie(q[r],q[r-1]))//维护单调队列 r--; r++; q[r]=i; } printf("%lld\n",dp[n]); }
以上是关于bzoj 1911 [Apio2010]特别行动队的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1911: [Apio2010]特别行动队 [斜率优化DP]