【BZOJ-3156】防御准备 DP + 斜率优化

3156: 防御准备

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 951  Solved: 446
[Submit][Status][Discuss]

Description

 

Input

第一行为一个整数N表示战线的总长度。

第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai。

Output

共一个整数,表示最小的战线花费值。

Sample Input

10
2 3 1 5 4 5 6 3 1 2

Sample Output

18

HINT

1<=N<=10^6,1<=Ai<=10^9

Source

Katharon+#1

Solution

斜率优化DP

方案由后面的转移? 翻转序列即可..

然后就是转移方程 $dp[i]=min(dp[i],dp[j]+sum[i-1]-sum[j]-(i-j-1)*j+A[i]$

然后斜率优化一下,比较的裸,然后即可

值得注意的地方:

转移的时候,$i=1$提前的处理出来..

在计算答案的时候,注意加long long否则会WA成狗..

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
#define maxn 1000100
int n,A[maxn]; int que[maxn],l,r;
long long dp[maxn],sumid[maxn],ans;
double slope(long long i,long long j)
{return (double)(dp[i]-dp[j]-sumid[i]+sumid[j]+i-j+i*i-j*j)/(double)(i-j);}
int main()
{
    n=read(); ans=(long long)1<<60;
    for (int i=n; i>=1; i--) A[i]=read();
    for (int i=1; i<=n; i++) sumid[i]=sumid[i-1]+i;
    dp[1]=A[1]; que[1]=1; l=r=1;
    for (int tmp,i=2; i<=n; i++)
        {
            while (l<r && slope(que[l],que[l+1])<i) l++;
            tmp=que[l];
            dp[i]=dp[tmp]+sumid[i-1]-sumid[tmp]-(i-tmp-1)*tmp+A[i];
            while (l<r && slope(que[r],i)<slope(que[r-1],que[r])) r--;
            que[++r]=i;
        }
    for (int i=1; i<=n; i++) ans=min(ans,dp[i]+sumid[n]-sumid[i]-(long long)(n-i)*i);
    printf("%lld
",ans);
    return 0;
}

上文所述WA成狗...MDZZ

原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5388392.html