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 }