【bzoj1010】玩具装箱toy——斜率优化dp

题目链接

第一道自己推的斜率优化dp><

首先要明确一点:装进同一个容器的toys一定要是连着的几个(否则的话可以直接贪心)-->之前理解错题意WA了一次......

用sum[i]表示前缀和,f[i]表示前i个装进容器的最小费用,

容易知道

  f[i]=max(f[i],f[j]+(sum[i]-sum[j]+i-(j+1)-l)2)(j<i)

令k<j<i,若要使f[j]>f[k],则需要满足:

  f[j]+(sum[i]-sum[j]+i-(j+1)-l)2<f[k]+(sum[i]-sum[k]+i-(k+1)-l)2

t[i]=sum[i]+i,则移项,可得:

  f[j]-f[k]+(t[j]-t[k])*(t[j]+t[k])<2(t[i]-l-1)(t[j]-t[k])

即:

  (f[j]-f[k]+t[j]2-t[k]2)/(t[j]-t[k])<2*(t[i]-l-1)

g[i]=f[i]+t[i]2,则有

  (g[j]-g[k])/(t[j]-t[k])<2*(t[i]-l-1)。

用s(i,j)表示i到j连线的斜率,

对于一个单调队列,每次对于队首,若s(q[h],q[h+1])<2*(ti-l-1),则此时的q[h]一定不会是现在和以后的最优解,h++;

对于队尾,若s(q[t-2],q[t-1])>s(q[t-1],i),如果s(q[t-2],q[t-1])<2*(t[i]-l-1),则s(q[t-1],i)<2*(t[i]-l-1),由i>q[t-1]可知此时i比q[t-1]要优;如果s(q[t-2],q[t-1])>2*(t[i]-l-1),则q[t-2]要比q[t-1]优。所以无论如何q[t-1]都不会是最优解,此时t--。

接着就是斜率优化dp的套路了:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 typedef long long LL;
 5 const int maxn=5e4+5;
 6 using namespace std;
 7 LL a[maxn],q[maxn],sum[maxn],g[maxn],t[maxn],f[maxn];
 8 inline LL read()
 9 {
10     LL anss=0,f=1;char c=getchar();
11     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
12     while(c>='0'&&c<='9'){anss=anss*10+c-48;c=getchar();}
13     return anss*f;
14 }
15 inline double cal(LL a,LL b)
16 {
17     return 1.0*(g[a]-g[b])/(t[a]-t[b]);
18 }
19 int main()
20 {
21     int n,l;
22     sum[0]=0;
23     scanf("%d %d",&n,&l);
24     for(int i=1;i<=n;i++){
25         a[i]=read();
26         sum[i]=sum[i-1]+a[i];
27         t[i]=sum[i]+i;
28     }
29     int h=0,ta=1;q[0]=0;
30     for(int i=1;i<=n;i++)
31     {
32         while(h<ta-1&&cal(q[h],q[h+1])<2*(t[i]-l-1))h++;
33         f[i]=f[q[h]]+(t[i]-t[q[h]]-l-1)*(t[i]-t[q[h]]-l-1);
34         g[i]=f[i]+t[i]*t[i];
35         while(h<ta-1&&cal(q[ta-1],q[ta-2])>cal(q[ta-1],i))ta--;
36         q[ta++]=i;
37     }
38     printf("%lld",f[n]);
39     return 0;
40 }
bzoj1010

 

posted @ 2017-08-31 21:02  Child-Single  阅读(208)  评论(0编辑  收藏  举报