【HNOI2008】玩具装箱 两种做法

题目评测在这里

http://www.lydsy.com/JudgeOnline/problem.php?id=1010

 

一道很明显的1D1D动态规划,方程很好写

f[i]=min{ f[j] + ( i-(j+1)+s[i]-s[j]-l )2}

 

直接写的话500000的数据量会让你明白。

 

两种做法:

 

①四边形不等式优化

  很明显的,用w[i+1,j]表示上述方程里的( i-(j+1)+s[i]-s[j]-l )2,不难验证这是个满足单调性的,也就是说对于这个方程,决策是单调的

  那么根据决策单调性,很自然的就有O(nlogn)的算法了

决策单调性
  1 /**
  2 *Prob    : HNOI 2008 toy
  3 *Sol    : 1D1D dp -- 决策单调性
  4 *Data    : 2012-6
  5 *Author : Zhou Hang
  6 */
  7 
  8 #include <cmath>
  9 #include <algorithm>
 10 #include <cstdio>
 11 #include <cstring>
 12 #include <iostream>
 13 
 14 #define MaxN 55000
 15 #define lld long long
 16 
 17 
 18 using namespace std;
 19 
 20 struct node
 21 {
 22     int x,y;//决策适用区间
 23     int pos; //由pos转移得到
 24 } q[MaxN];
 25 
 26 int n,l;
 27 lld f[MaxN],c[MaxN];
 28 
 29 lld sqr(lld x)
 30 {
 31     return x*x;
 32 }
 33 
 34 lld cal(int x,int y)
 35 {
 36     return sqr(x-(y+1)+(c[x]-c[y])-l)+f[y];
 37 }
 38 
 39 void dp()
 40 {
 41     memset(f,127,sizeof(f));
 42     f[0]=0;
 43     int head=1,tail=1;
 44     q[1].x=1; q[1].y=n; q[1].pos=0;
 45     
 46     int l,r,mid;
 47     
 48     for (int i=1; i<=n; i++)
 49     {
 50         //算出f[i]
 51         f[i]=cal(i,q[head].pos);
 52         if (i+1>q[head].y) head++;
 53         
 54         //差的决策整体淘汰
 55         while (head<=tail && cal(q[tail].x,i)<cal(q[tail].x,q[tail].pos) )
 56             tail--;
 57         
 58         //对列为空
 59         if (head>tail)
 60         {
 61             q[++tail].x=i+1;
 62             q[tail].y=n; q[tail].pos=i;
 63             continue;
 64         }
 65         
 66         //二分,留下当前决策的一部分
 67         l=q[tail].x; r=q[tail].y+1;
 68         while (l+1<r)
 69         {
 70             mid=(l+r)/2;
 71             if ( cal(mid,i)<cal(mid,q[tail].pos) ) r=mid;
 72             else l=mid;
 73         }
 74         if (r>=n+1) continue;
 75         
 76         q[tail].y=l;
 77         q[++tail].x=r;
 78         q[tail].y=n;
 79         q[tail].pos=i;
 80     }
 81     
 82 }
 83 
 84 
 85 int main()
 86 {
 87     freopen("toy.in","r",stdin);
 88     freopen("toy.out","w",stdout);
 89     
 90     scanf("%d%d",&n,&l);
 91     c[0]=0;
 92     for (int i=1; i<=n; i++)
 93     {
 94         scanf("%d",&c[i]);
 95         c[i]+=c[i-1];
 96     }
 97     
 98     dp();
 99     
100     cout<<f[n]<<endl;
101     
102     fclose(stdin); fclose(stdout);
103     return 0;
104 }

 

②斜率优化 O(n)

  个人觉得实际上斜率优化就是凸完全单调性的一种特殊情况,关于斜率优化的使用方法,这个人条理很清晰,觉得很好,受到了很大启发

  在这里谢一声http://blog.sina.com.cn/s/blog_5e6fc6d60100vp2j.html

  关于斜率优化的讲解,http://wenku.baidu.com/view/d3d979dcd15abe23482f4d58.html这个里面讲的很好

  这道题直接说化简方程后的结果了:((f[x]+s'[x]*s'[x])-(f[y]+s'[y]*s'[y]))/(s'[x]-s'[y])>2*(s'[i]-L')    其中s'[i]=s[i]+i,L'=L+1

  G(x,y)=((f[x]+s'[x]*s'[x])-(f[y]+s'[y]*s'[y]))/(s'[x]-s'[y])

  具体看代码

斜率优化
 1 /**
 2 *Prob    : HNOI 2008 toy
 3 *Sol    : 1D1D dp -- 斜率优化
 4 *Data    : 2012-6
 5 *Author : Zhou Hang
 6 */
 7 
 8 #include <cmath>
 9 #include <algorithm>
10 #include <cstdio>
11 #include <cstring>
12 #include <iostream>
13 
14 #define MaxN 55000
15 #define lld long long
16 
17 using namespace std;
18 
19 int q[MaxN];
20 int n,l;
21 lld f[MaxN],s[MaxN];
22 
23 double G(int x,int y)
24 {
25     return ((f[x]+s[x]*s[x])-(f[y]+s[y]*s[y]))/(s[x]-s[y]);
26 }
27 
28 
29 void dp()
30 {
31     memset(f,127,sizeof(f));
32     f[0]=0; q[1]=0;
33     int head=1,tail=1;
34     
35     for (int i=1;i<=n;++i)    
36     {
37         while (head<tail && G(q[head],q[head+1])<=2*(s[i]-l-1))
38             head++;
39 
40         f[i]=f[q[head]]+(s[i]-s[q[head]]-1-l)*(s[i]-s[q[head]]-1-l);
41 
42         while (head<tail && G(q[tail-1],q[tail])>=G(q[tail],i))
43             tail--;
44         q[++tail]=i;
45     }
46     cout<<f[n]<<"\n";
47 }
48 
49 int main()
50 {
51     freopen("toy.in","r",stdin);
52     freopen("toy.out","w",stdout);
53 
54     scanf("%d%d",&n,&l);
55     s[0]=0;
56     for (int i=1; i<=n; i++)
57     {
58         scanf("%d",&s[i]);
59         s[i]+=s[i-1]+1;
60     }
61     //s'[i]=s[i]+n 用s[i]存s'[i]
62     
63     dp();
64 
65 
66     fclose(stdin); fclose(stdout);
67     return 0;
68 }

 

 

 

posted @ 2012-06-07 11:30  守護N1身边  阅读(485)  评论(0编辑  收藏  举报