当前位置: 代码迷 >> 综合 >> 【HNOI2008】玩具装箱
  详细解决方案

【HNOI2008】玩具装箱

热度:48   发布时间:2023-12-05 12:33:36.0

题面


??n5?104,0LCi107

解法

??我们可以得出一个n2的DP:设f[i]表示决策完第i件玩具的最小花费, s[i]=ik=1Ci ,那么有:f[i]=min{ f[j]+(s[i]?s[j]+i?j?1?l)2}
??将里面的式子展开可以得到:f[j]+(s[i]+i)2+(s[j]+j)2+(l+1)2?2?(s[i]+i)?(s[j]+j)?2?(s[i]+i)?(l+1)+2?(s[j]+j]?(l+1)
??其中,(s[i]+i)2(l+1)2?2?(s[i]+i)?(l+1)属于和j无关的量,直接拉出来,剩下的部分为: f[j]+(s[j]+j)2?2?(s[j]+j)?(s[i]+i?l?1)
??假设i可以从 j 以及k转移得来,并且从 k 转移更优,那么有:

f[j]+(s[j]+j)2?2?(s[j]+j)?(s[i]+i?l?1)<f[k]+(s[k]+k)2?2?(s[k]+k)?(s[i]+i?l?1)

f[j]+(s[j]+j)2?f[k]?(s[k]+k)22?[(s[j]+j)?(s[k]+k)]<s[i]+i?l?1······

??接下来就只需要根据式①进行斜率优化的过程就可以了

复杂度

O(nlogn

代码

#include<iostream>
#include<cstdlib>
#include<cstdio>
#define Rint register int
#define Lint long long int
using namespace std;
const int N=50010;
Lint s[N],f[N];
int q[N],c[N],n,L,head,tail;;
Lint getup(int i,int j)
{return f[i]+(s[i]+i)*(s[i]+i)-f[j]-(s[j]+j)*(s[j]+j);
}
Lint getdown(int i,int j)
{return 2*(s[i]+i-s[j]-j);
}
bool judge(int i,int j,int C)
{Lint A=getup( i,j ),B=getdown( i,j );return A<=B*C;
}
bool Judge(int i,int j,int k)
{return getup( i,j )*getdown( j,k )<=getup( j,k )*getdown( i,j );
}
Lint cal(int i,int j)
{return f[j]+(s[i]-s[j]+i-j-1-L)*(s[i]-s[j]+i-j-1-L);
}
int main()
{scanf("%d%d",&n,&L);for(int i=1;i<=n;i++){scanf("%d",&c[i]);s[i]=s[i-1]+c[i];}head=tail=q[0]=0;for(int i=1;i<=n;i++){while( head+1<=tail && judge( q[head+1],q[head],s[i]+i-L-1 ) )   ++head;f[i]=cal( i,q[head] );while( head+1<=tail && Judge( i,q[tail],q[tail-1] ) )   tail--;q[++tail]=i;}printf("%lld\n",f[n]);return 0;
}