HDU - 3507 Print Article (斜率DP优化)

 1 #include <iostream>
 2 #include <queue>
 3 #include <stack>
 4 #include <cstdio>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <bitset>
 9 #include <algorithm>
10 #include <cmath>
11 #include <cstring>
12 #include <cstdlib>
13 #include <string>
14 #include <sstream>
15 #include <time.h>
16 #define x first
17 #define y second
18 #define pb push_back
19 #define mp make_pair
20 #define lson l,m,rt*2
21 #define rson m+1,r,rt*2+1
22 #define mt(A,B) memset(A,B,sizeof(A))
23 #define lowbit(x) (x&(-x))
24 using namespace std;
25 typedef long long LL;
26 //const double PI = acos(-1);
27 const int N=5e5+10;
28 const LL mod=1e9+7;
29 const int inf = 0x3f3f3f3f;
30 const LL INF=0x3f3f3f3f3f3f3f3fLL;
31 const double esp=1e-10;
32 int n,q[N];
33 LL m,sum[N],dp[N];
34 //dp的斜率优化就是把那些没用的点舍弃,降低尝试次数从而提高效率。
35 //如果up(j,k)/down(j,k)<=sum[i],则说明位置j比位置k更优,则位置k可以直接舍弃。
36 //维护一个下凸折线,用单调队列维护,类似凸包的维护。
37 LL up(int j,int k)//斜率优化时的分子
38 {
39     return dp[j]+sum[j]*sum[j]-dp[k]-sum[k]*sum[k];
40 }
41 LL down(int j,int k)//斜率优化时的分母
42 {
43     return 2*sum[j]-2*sum[k];
44 }
45 int main()
46 {
47 #ifdef Local
48     freopen("data.txt","r",stdin);
49 #endif
50     ios::sync_with_stdio(false);
51     cin.tie(0);
52     while(cin>>n>>m)
53     {
54         int head=0,tail=0;
55         sum[0]=0;dp[0]=0;
56         for(int i=1;i<=n;i++)
57         {
58             cin>>sum[i];
59             sum[i]+=sum[i-1];
60         }
61         q[tail++]=0;
62         for(int i=1;i<=n;i++)
63         {
64             //从head开始寻找,如果满足up(q[head+1],q[head])/down(q[head+1],q[head])<=sum[i]则说明q[head+1]的点优于q[head]点,直接跳过
65             while(head+1<tail&&up(q[head+1],q[head])<=sum[i]*down(q[head+1],q[head]))head++;
66             dp[i]=dp[q[head]]+(sum[i]-sum[q[head]])*((sum[i]-sum[q[head]]))+m;
67             //新加入的i点可能与原来单调队列中的点形成上凸折线,所以需要把那些形成上凸折线的点剔除掉。
68             //即如果k(i,q[tail-1])<k(q[tail-1],q[tail-2]),则形成上凸折线,q[tail-1]该点必须剔除。
69             //最后再把i点加入单调队列。
70             while(head+1<tail&&up(q[tail-1],q[tail-2])*down(i,q[tail-1])>=down(q[tail-1],q[tail-2])*up(i,q[tail-1]))tail--;
71             q[tail++]=i;
72         }
73         cout<<dp[n]<<endl;
74     }
75     return 0;
76 #ifdef Local
77     cerr << "time: " << (LL) clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
78 #endif
79 }

 

posted @ 2017-05-18 20:25  Kcl886  阅读(178)  评论(0编辑  收藏  举报