BZOJ1010

1010: [HNOI2008]玩具装箱toy

思路:斜率优化

Fi 为前 i 个玩具的最优答案
递推式: Fi=Min { Fj+(ij1+sumisumjL)2 }

斜率优化的思想咯:若j比k优,则有
Fj+(ij1+sumisumjL)2<Fk+(ik1+sumisumkL)2
基本数学知识可以化成:
[Fk+(sumk+k+L+1)2][Fj+(sumj+j+L+1)2]>2(sumk+ksumjj)(sumi+i)

sumi i 都是单调递增的,除过去用朴素的斜率优化就好

代码:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int MAXN=50010;
typedef long long ull;
int n,L;
ull c[MAXN];
ull sum[MAXN];
ull f[MAXN];
int stack[MAXN];
int l,r;
ull a(int i) { return sum[i]+i; }
ull x(int i) { return 2*a(i); }
ull y(int i) { return f[i]+(a(i)+L+1)*(a(i)+L+1); }
void init()
{
    cin>>n>>L;
    for (int i=1;i<=n;i++) {
        scanf("%I64d",&c[i]);
        sum[i]=sum[i-1]+c[i]; }
    l=r=0;
    for (int i=1;i<=n;i++) {
        while (lstack[l+1])-y(stack[l]))<=a(i)*(x(stack[l+1])-x(stack[l])))
            stack[l++]=0;
        f[i]=f[stack[l]]+(i-stack[l]-1+sum[i]-sum[stack[l]]-L)*(i-stack[l]-1+sum[i]-sum[stack[l]]-L);
        while (l<=r && (y(i)-y(stack[r-1]))*(x(i)-x(stack[r]))>(y(i)-y(stack[r]))*(x(i)-x(stack[r-1])))
            stack[r--]=0;
        stack[++r]=i; }
    cout<return ;
}
int main()
{
    init();
    return 0;
}

你可能感兴趣的:(BZOJ)