【bzoj1911】[Apio2010]特别行动队 DP斜率优化

Description

【bzoj1911】[Apio2010]特别行动队 DP斜率优化_第1张图片

Input

http://www.lydsy.com/JudgeOnline/images/1911_2.jpg

Output

http://www.lydsy.com/JudgeOnline/images/1911_3.jpg

Sample Input

4 

-1 10 -20 

2 2 3 4 

Sample Output

9

HINT

【bzoj1911】[Apio2010]特别行动队 DP斜率优化_第2张图片

Source

易写出状态转移方程:

fi=max(fj+A(SiSj)2+B(SiSj)+C)

Si 是前缀和。

然后,设 j<k 且j比k优。

fj+A(SiSj)2+B(SiSj)+C>fk+A(SiSk)2+B(SiSk)+C

fjfk+A(2SiSjSk)(SkSj)+B(SkSj)>0

fj+S2j2ASiSjBSj>fk+S2k2ASiSkBSk

Gj=fj+AS2jBSj Hj=2ASj

可得

GjGkHjHk<Si

完了。

这样若队头两元素不满足这个式子,则弹出。因为是小于S,所以维护单减的斜率。

不开longlong会死

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

typedef long long LL;
const int SZ = 1000010;
const int INF = 1000000010;

LL dp[SZ],s[SZ];
int n;
LL a,b,c;

LL q[SZ],t = 0,w = 0;

LL G(int x)
{
    return dp[x] + a * s[x] * s[x] - b * s[x];
}

LL H(int x)
{
    return -2 * a * s[x];
}

double xl(int x,int y)
{
    return (G(x) - G(y)) / (double)(H(x) - H(y));
}

int main()
{
    scanf("%d%lld%lld%lld",&n,&a,&b,&c);
    for(int i = 1;i <= n;i ++)
    {
        int x;
        scanf("%d",&x);
        s[i] = s[i - 1] + x;
    }
    for(int i = 1;i <= n;i ++)
    {
        while(t < w && xl(q[t],q[t + 1]) > -s[i]) t ++;
        int x = q[t];
        LL y = s[i] - s[x];
        dp[i] = dp[x] + a * y * y + b * y + c;
        while(t < w && xl(q[w - 1],q[w]) < xl(q[w],i) ) w --;
        q[++ w] = i;
    }
    printf("%lld",dp[n]);
    return 0;
}




你可能感兴趣的:(【bzoj1911】[Apio2010]特别行动队 DP斜率优化)