BZOJ - 1010【斜率优化DP】
1010: [HNOI2008]玩具装箱toy
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 9961 Solved: 4056
[Submit][Status][Discuss]
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
3
4
2
1
4
Sample Output
1
题解:很朴素的n^2DP是显然的,设dp[i]为完成前i个任务的最小花费 。
则dp[i] = min(dp[j] + (sum[i]-sum[j]+i-j-1-L)^2);但是会超时的,就去学了斜率优化。具体见博客。
代码:
1 /************************************************************** 2 Problem: 1010 3 User: Jstyle 4 Language: C++ 5 Result: Accepted 6 Time:176 ms 7 Memory:2844 kb 8 ****************************************************************/ 9 10 #include <iostream> 11 #include <algorithm> 12 #include <cstring> 13 #include <cstdlib> 14 #include <cstdio> 15 #include <bitset> 16 #include <vector> 17 #include <queue> 18 #include <stack> 19 #include <cmath> 20 #include <list> 21 #include <set> 22 #include <map> 23 #define rep(i,a,b) for(int i = a;i <= b;++ i) 24 #define per(i,a,b) for(int i = a;i >= b;-- i) 25 #define mem(a,b) memset((a),(b),sizeof((a))) 26 #define FIN freopen("in.txt","r",stdin) 27 #define FOUT freopen("out.txt","w",stdout) 28 #define IO ios_base::sync_with_stdio(0),cin.tie(0) 29 #define mid ((l+r)>>1) 30 #define ls (id<<1) 31 #define rs ((id<<1)|1) 32 #define N 50005 33 #define INF 0x3f3f3f3f 34 #define INFF ((1LL<<62)-1) 35 typedef long long LL; 36 using namespace std; 37 38 LL n, q[N],L, a[N], dp[N], sum[N]; 39 40 double cal(int x, int y){ 41 return (dp[x]-dp[y]+sum[x]*sum[x]-sum[y]*sum[y])*1.0/(sum[x]-sum[y]); 42 } 43 void Init(){ 44 mem(dp, 0); 45 mem(sum, 0); 46 } 47 int main() 48 {IO; 49 //FIN; 50 while(cin >> n >> L){ 51 Init(); 52 rep(i, 1, n){ 53 cin >> a[i]; 54 sum[i] = sum[i-1] + a[i] + 1; 55 } 56 int l = 0, r = 0; 57 rep(i, 1, n){ 58 while(l < r && cal(q[l], q[l+1]) <= 2*(sum[i]-1-L)) l++; 59 int id = q[l]; 60 dp[i] = dp[id]+(sum[i]-sum[id]-1-L)*(sum[i]-sum[id]-1-L); 61 while(l < r && cal(q[r], i) < cal(q[r-1], q[r])) r--; 62 q[++r] = i; 63 } 64 cout << dp[n] << endl; 65 } 66 return 0; 67 }