zoukankan      html  css  js  c++  java
  • BZOJ 1911: [Apio2010]特别行动队 斜率优化dp

    1911: [Apio2010]特别行动队

    题目连接:

    http://www.lydsy.com/JudgeOnline/problem.php?id=1911

    Description

    有n个数,然后你需要把这n个数分成若干段,每段的权值是a*sum*sum+b*sum+c

    问你怎么切,使得权值和最大

    sum表示该区间的权值和

    Input

    三行 n,a,b,c 然后n个数,表示每个数的权值

    Output

    答案

    Sample Input

    4

    -1 10 -20

    2 2 3 4

    Sample Output

    9

    数据范围n,b,c为1e6,a为5

    Hint

    题意

    题解:

    斜率优化dp

    n^2 dp很显然,dp[i] = max(dp[j]+w[i][j])

    这个模式比较显然的是斜率优化dp的模式

    方程,假设i>j,且i优于j,则可以化为 dp[i]-dp[j]+a*(sum[i]*sum[i]-sum[j]*sum[j])+b*(sum[j]-sum[i]) / 2*a*(sum[i]-sum[j]) <sum[i]

    然后斜率优化dp跑一波就好了

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6+5;
    int n;
    long long a,b,c;
    long long x;
    long long sum[maxn];
    long long dp[maxn];
    double slope(int i,int j)
    {
        double up = dp[i]-dp[j]+a*(sum[i]*sum[i]-sum[j]*sum[j])+b*(sum[j]-sum[i]);
        double down = 2*a*(sum[i]-sum[j]);
        return up/down;
    }
    int l,r,q[maxn];
    int main()
    {
        scanf("%d",&n);
        scanf("%lld%lld%lld",&a,&b,&c);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&x);
            sum[i]=sum[i-1]+x;
        }
        for(int i=1;i<=n;i++)
        {
            while(l<r&&slope(q[l+1],q[l])<sum[i])l++;
            int now = q[l];
            dp[i]=dp[now]+a*(sum[i]-sum[now])*(sum[i]-sum[now])+b*(sum[i]-sum[now])+c;
            while(l<r&&slope(q[r],q[r-1])>slope(i,q[r]))r--;
            q[++r]=i;
        }
        printf("%lld
    ",dp[n]);
    }
  • 相关阅读:
    Azureus 3.0.0.8
    KchmViewer 3.0
    GNOME 2.18.0 正式版颁发宣布
    Emacs 22.0.95
    gTwitter:Twitter 的 Linux 客户端
    KDE DVD Authoring Wizard-易用的 DVD 制造器材
    GIMP 2.3.15
    Monit-零碎看监工具
    Cobras-专注于 Qt 的 IDE
    K3b 1.0 正式版公布
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5179656.html
Copyright © 2011-2022 走看看