Print Article(斜率DP入门+单调队列)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3507

题目大意:给你n个数,然后问你怎么分割当前的这n个数位那几组,使得每一组的权值加起来最大。每一组权值的计算方法在题目上说了。

具体思路: 一开始打了一波两重for循环的,一直求一个tile,但是wa了。然后就学了斜率优化的方法

https://www.cnblogs.com/ka200812/archive/2012/08/03/2621345.html

就是把表达式转换成斜率类型的表达式,然后对于当前的节点,通过判断斜率的方式来决定当前的点是不是该选择,这个过程可以用单调队列维护。

AC代码:

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<cmath>
 4 using namespace std;
 5 # define ll long long
 6 const int maxn = 6e5+100;
 7 int sum[maxn];
 8 int q[maxn];
 9 int dp[maxn];
10 int n,m;
11 int getdp(int i,int j){
12 return dp[i]+m+(sum[j]-sum[i])*(sum[j]-sum[i]);
13 }
14 int getup(int i,int j){
15 return dp[i]+sum[i]*sum[i]-(dp[j]+sum[j]*sum[j]);
16 }
17 int getdown(int i,int j){
18 return 2*(sum[i]-sum[j]);
19 }
20 int main(){
21 while(~scanf("%d %d",&n,&m)){
22 for(int i=1;i<=n;i++){
23 scanf("%d",&sum[i]);
24 sum[i]+=sum[i-1];
25 }
26 int tail,head;
27 tail=head=0;
28 q[tail++]=0;
29 
30 for(int i=1;i<=n;i++){
31 while(head+1<tail&&getup(q[head+1],q[head])<=sum[i]*getdown(q[head+1],q[head]))head++;
32 dp[i]=getdp(q[head],i);
33 while(head+1<tail&&getdown(q[tail-2],q[tail-1])*getup(q[tail-1],i)<=getdown(q[tail-1],i)*getup(q[tail-2],q[tail-1]))tail--;
34 q[tail++]=i;
35 }
36 printf("%d\n",dp[n]);
37 }
38 return 0;
39 }

 

posted @ 2019-03-19 15:11  Let_Life_Stop  阅读(293)  评论(0编辑  收藏  举报