bzoj1010 [HNOI2008]玩具装箱toy

1010: [HNOI2008]玩具装箱toy

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 7065  Solved: 2684

Description

P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为x,其制作费用为(X-L)^2.其中L是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过L。但他希望费用最小.

Input

第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7

Output

输出最小费用

Sample Input

5 4
3
4
2
1
4

Sample Output

1

HINT

 

Source

 

题目大意:给n个玩具,每个玩具有权值C[i],分成几组,每组的值=组内玩具的权值之和+∑C[i]以及组内玩具个数-1,每组的代价=(每组的值-L)^2 ,问最优分组后的代价之和(即各组代价相加)

分析:首先,很快想到一个O(n^2)的做法,即Dp[i]表示前 i 个分组后的最小代价和,每次枚举一个 j,表示第 j+1 到 i 个分成一组,

转移为 DP[i] = MIN(DP[j]+( C[j+1]+C[j+2]+....+C[i]+i-j-1-L)^2   ),0 <= j < i

若设 Sum[i] = C[1]+C[2]+....C[i]

则转移为 DP[i] = MIN(DP[j]+ ( Sum[i]-Sum[j]+i-j-1-L)^2   ),0 <= j < i

再设 S[i] = Sum[i]+i

则转移为 DP[i] = MIN(DP[j]+  (S[i]-S[j]-1-L)^2  ),0 <= j < i

 

那么,对这个方程进行探究:

对于两个决策点k,j(k > j)

若选择在k+1....i 分组优于在 j+1...i 分组(即决策点k优于决策点 j ),则有

      Dp[k]+(S[i]-S[k]-1-L)^2 < Dp[j]+(S[i]-S[j]-1-L)^2

->  Dp[k] + (S[i]-1-L)^2 + S[k]^2 - 2*(S[i]-1-L)*S[k] < Dp[j] + (S[i]-1-L)^2 + S[j]^2 - 2*(S[i]-1-L)*S[j]

->  (Dp[k]+S[k]^2) - (Dp[j]+s[j]^2) < 2*(S[i]-1-L)*(S[k]-S[j])

->  [ (Dp[k]+S[k]^2) - (Dp[j]+s[j]^2) ] / (S[k]-S[j]) < 2*(S[i]-1-L)

->  即点(S[k], Dp[k]+S[k]^2)与点(S[j],Dp[j]+s[j]^2 )的斜率 < 2*(S[i]-1-L)

也就是说,若决策点k优于决策点j则必定有上式成立

显然对于固定的两点 j、k   ,(S[i]-1-L)的值是递增的(因为 i 是递增的),

所以 对于任意的j、k都有这样情况,若当 i = x时,有决策点k优于决策点j,那么当 i = x+1, i = x+2, ......, i = n时,都有决策点k优于决策点j

所以我们可以维护一个单调递增的决策点队列x1,x2,x3,.....xn,并使得它们相邻点之间的斜率递增,

这样,随着(s[i]-1-L)的增加,不断维护队列中的点(即不断删除队头即可,因斜率递增)

每次算完Dp[i]后,显然我们要将 i 也作为决策点加入队列,在加入前,我们需考虑一点东西

假设队尾前一个为x,队尾为y,

若x、y的斜率大于y,i 的斜率,那么显然,决策点绝不可能是y(因为如果有x、y的斜率小于2*(S[i]-1-L),则必有y,i的斜率小于2*(s[i]-1-L)),并且如果保留y,还会影响决策(因为在维护队列的过程中,只看队头,要保持单调递增),所以要删去 y,

在不断的删去不合格的队尾后,再将决策点 i 加入

 

综上所述,本题得解

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <deque>
  6 #include <vector>
  7 #include <queue>
  8 #include <iostream>
  9 #include <algorithm>
 10 #include <map>
 11 #include <set>
 12 #include <ctime>
 13 using namespace std;
 14 typedef long long LL;
 15 typedef double DB;
 16 #define For(i, s, t) for(int i = (s); i <= (t); i++)
 17 #define Ford(i, s, t) for(int i = (s); i >= (t); i--)
 18 #define MIT (2147483647)
 19 #define INF (1000000001)
 20 #define MLL (1000000000000000001LL)
 21 #define sz(x) ((int) (x).size())
 22 #define clr(x, y) memset(x, y, sizeof(x))
 23 #define puf push_front
 24 #define pub push_back
 25 #define pof pop_front
 26 #define pob pop_back
 27 #define ft first
 28 #define sd second
 29 #define mk make_pair
 30 inline void SetIO(string Name) {
 31     string Input = Name+".in",
 32     Output = Name+".out";
 33     freopen(Input.c_str(), "r", stdin),
 34     freopen(Output.c_str(), "w", stdout);
 35 }
 36 
 37 const int N = 50010;
 38 int n;
 39 LL L;
 40 LL C[N], Sum[N], S[N], Dp[N];
 41 int Que[N], Head, Tail;
 42 
 43 inline LL Getint() {
 44     char Ch = ' ';
 45     LL Ret = 0;
 46     while(!(Ch >= '0' && Ch <= '9')) Ch = getchar();
 47     while(Ch >= '0' && Ch <= '9') {
 48         Ret = Ret*10LL+Ch-'0';
 49         Ch = getchar();
 50     }
 51     return Ret;
 52 }
 53 
 54 inline void Input() {
 55     scanf("%d", &n);
 56     L = Getint();
 57     For(i, 1, n) C[i] = Getint();
 58 }
 59 
 60 inline LL Sqr(LL x) {
 61     return x*x;
 62 }
 63 
 64 inline bool Better(int x, int y, int i) {
 65     return Dp[x]+Sqr(S[x])-Dp[y]-Sqr(S[y]) 
 66         <= 2LL*(S[i]-L-1)*(S[x]-S[y]);
 67 }
 68 
 69 inline bool Smaller(int x, int y, int z) {
 70     LL DX1 = S[y]-S[x], DX2 = S[z]-S[y],
 71         DY1 = Dp[y]+Sqr(S[y])-Dp[x]-Sqr(S[x]), 
 72         DY2 = Dp[z]+Sqr(S[z])-Dp[y]-Sqr(S[y]);
 73     return DY1*DX2 <= DY2*DX1;
 74 }
 75 
 76 inline void Solve() {
 77     For(i, 1, n) Sum[i] = Sum[i-1]+C[i];
 78     For(i, 1, n) S[i] = Sum[i]+i;
 79     
 80     Head = Tail = 1, Que[1] = 0;
 81     For(i, 1, n) {
 82         int x, y;
 83         while(Head < Tail) {
 84             x = Que[Head], y = Que[Head+1];
 85             if(Better(x, y, i)) break;
 86             Head++;
 87         }
 88         
 89         x = Que[Head];
 90         Dp[i] = Dp[x]+Sqr(S[i]-S[x]-1-L);
 91         
 92         while(Head < Tail) {
 93             x = Que[Tail-1], y = Que[Tail];
 94             if(Smaller(x, y, i)) break;
 95             Tail--;
 96         }
 97         Que[++Tail] = i;
 98     }
 99     
100     cout<<Dp[n]<<endl;
101 }
102 
103 int main() {
104     SetIO("1010");
105     Input();
106     Solve();
107     return 0;
108 }
View Code

 

posted @ 2015-06-21 22:35  yanzx6  阅读(184)  评论(0编辑  收藏  举报