• 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,则得到

    $2asum[i](sum[k]-sum[j])>dp[k]+asum[i]^{2}-bsum[k]-(dp[j]+asum[i]^{2}-bsum[j])$

    令$f[x]=dp[x]+asum[x]^{2}-bsum[x]$

    $2asum[i](sum[k]-sum[j])>f[k]-f[j]$

    $2asum[i]>frac{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
    ",dp[n]);
    }
  • 相关阅读:
    C语言I博客作业07
    C语言I博客作业06
    C语言I博客作业05
    C语言I博客作业04
    C语言II博客作业04
    C语言II博客作业03
    C语言II博客作业01
    学期总结
    C语言I博客作业08
    C语言I博客作业07
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/10617889.html
Copyright © 2020-2023  润新知