记录编号 175707 评测结果 AAAAAAAAAA
题目名称 [HNOI 2008]玩具装箱toy 最终得分 100
用户昵称 Gravatar0 是否通过 通过
代码语言 C++ 运行时间 0.327 s
提交时间 2015-08-06 20:39:31 内存使用 1.44 MiB
显示代码纯文本
/******************************************************************************
朴素方程:f[i]=f[k]+(i-k-1-L+s[i]-s[k])^2 (s数组为前缀和,将j+1~i放入一个容器中)
优化:设k>j且k优于j 
   则f[k]+(i-k-1-L+s[i]-s[k])^2<=f[j]+(i-j-1-L+s[i]-s[j])^2
   当i确定时,可以发现式中有许多常量,即O(1) 即可得出的与i有关的量
   设p=i+s[i]-L-1,则原式可化简为
      f[k]+(p-(s[k]+k))^2<=f[j]+(p-(s[j]+j))^2
   再化简
      f[k]+p^2-2*p*(s[k]+k)+(s[k]+k)^2<=f[j]+p^2-2*p*(s[j]+j)+(s[j]+j)^2 
      f[k]-2*p*(s[k]+k)+(s[k]+k)^2<=f[j]-2*p*(s[j]+j)+(s[j]+j)^2 
   移项,将常量移到一边,变量移到另一边
      f[k]-f[j]+(s[k]+k)^2-(s[j]+j)^2<=2*p*((s[j]+j)-(s[k]+k)) 
      f[k]-f[j]+(s[k]+k)^2-(s[j]+j)^2  /  ((s[k]+k)-(s[j]+j)) <=2*p
*********************************************************************************
   设i>j>k
      g[i,j]= f[i]-f[j]+(s[i]+i)^2-(s[j]+j)^2  /  ((s[i]+i)-(s[j]+j))
      g[j,k]同理 
   由上面得出若k>j 则当g[k,j]<=2*p(p=i-L-1+s[i])时  k优于j
   且我们发现,随着i的递增,p是单调不减的 。即对于i来说,若小于它的j不是最优解
   也就是存在k优于j,那么对于大于i的q来说,k也一定优于j,这就使得本题可以使用单调队列优化
   现在来讨论出队的条件
**********************************************************************************
   (1)g[k,j]<2*p (k>j) j可直接出队
   (2)g[i,k]<g[k,j](i>k>j)
       若g[i,k]<2*p    i优于k  k出队
       若g[i,k]>2*p    则g[k,j]>2*p   j比k优,k出队
   (3)g[i,k]>g[k,j] 
       g[k,j]>2*p j比k优
       g[k,j]<2*p g[i,j]无法确定,k不确定是否出队 
***********************************************************************************/
 
#include<cstdio>
 
using namespace std;
 
int n,l,q[100010];
long long f[50010],s[50010];
 
long long g(int x,int y)
{
     return f[x]-f[y]+(s[x]+x)*(s[x]+x)-(s[y]+y)*(s[y]+y);
}
 
long long a(int x,int y)
{
    return (s[x]+x)-(s[y]+y);
}
 
int main()
{
    freopen("bzoj_1010.in","r",stdin);
	freopen("bzoj_1010.out","w",stdout);
    scanf("%d%d",&n,&l);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&s[i]);
        s[i]+=s[i-1];
    }
    int head=0,tail=0;q[tail]=0;f[0]=0;
    for(int i=1;i<=n;i++)
    {
        long long p=i-l-1+s[i];
        while(head<=tail&&g(q[head+1],q[head])<2*p*a(q[head+1],q[head]))head++;
        f[i]=f[q[head]]+(p-s[q[head]]-q[head])*(p-s[q[head]]-q[head]);
        while(head<=tail&&g(q[tail],q[tail-1])*a(i,q[tail])>g(i,q[tail])*a(q[tail],q[tail-1]))tail--;q[++tail]=i;
    }
    printf("%lld",f[n]);
    //while(1);
}