#HDU3507#Print Article(DP+斜率优化)
来源:互联网 发布:抛光砖 抛釉砖 知乎 编辑:程序博客网 时间:2024/05/17 05:06
Print Article
Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 12253 Accepted Submission(s): 3758
One day Zero want to print an article which has N words, and each word i has a cost Ci to be printed. Also, Zero know that print k words in one line will cost
M is a const number.
Now Zero want to know the minimum cost in order to arrange the article perfectly.
5 559575
230
题目大意:输出N个数字a[N],输出的时候可以连续的输出,每连续输出一串,它的费用是 “这串数字和的平方加上一个常数M”。n<=500000
设dp[i]表示输出到i的时候最少的花费,sum[i]表示从a[1]到a[i]的数字和。
dp[i]=dp[j]+M+(sum[i]-sum[j])^2
设k<j<i。如果在j的时候决策要比在k的时候决策好,那么也是就是dp[j]+M+(sum[i]-sum[j])^2<dp[k]+M+(sum[i]-sum[k])^2。
两边移项一下,得到:(dp[j]+sum[j]^2-(dp[k]+sum[k]^2))/(2*(sum[j]-sum[k]))<sum[i]。我们把dp[j]+sum[j]^2看做是yj,把2*sum[j]看成是xj。
说明g[j,k]=(yj-yk)/(xj-xk)<sum[i]代表这j的决策比k的决策要更优。
若k<j<i且g[i,j]<g[j,k],则j点永远不可能成为最优解。
分三种情况讨论:
设当前点为a
1.如果g[i,j]与g[j,k]均小于sum[a],则i比j优,j比k优
2.如果g[i][j]与g[j,k]均大于sum[a],则k比j优,j比i优。
3.如果g[i][j]<sum[a]且g[i][j]>sum[a],则i比j优,k比j优。
不论如何,j都无法成为最佳决策点,所以可以排除j。
于是,所有的决策点满足一个下凸包性质。
设k<j<i。
由于我们排除了g[i,j]<g[j,k]的情况,所以整个有效点集呈现一种下凸性质,即g[i,j]>g[j,k]。
这样,从左到右,斜率之间就是单调递增的了。当我们的最优解取得在j点的时候,那么k点不可能再取得比j点更优的解了,于是k点也可以排除。换句话说,j点之前的点全部不可能再比j点更优了,可以全部从解集中排除。
1,用一个单调队列来维护解集。
2,假设队列中从头到尾已经有元素a b c。那么当d要入队的时候,我们维护队列的下凸性质,即如果g[d,c]<g[c,b],那么就将c点删除。直到找到g[d,x]>=g[x,y]为止,并将d点加入在该位置中。
3,找最佳决策点时,设当前求解状态为i,从队头开始,如果已有元素a b c,当i点要求解时,如果g[b,a]<sum[i],那么说明b点比a点更优,a点可以排除,于是a出队,直到第一次遇到g[j,j-1]>sum[i],此时j-1即为最佳决策点。
Code:
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;const int Max = 500000;int N, M;int sum[Max + 5], Q[Max + 5], Dp[Max + 5];bool getint(int & num){ char c; int flg = 1; num = 0; while((c = getchar()) < '0' || c > '9'){ if(c == '-') flg = -1; if(c == -1) return 0; } while(c >= '0' && c <= '9'){ num = num * 10 + c - 48; if((c = getchar()) == -1) return 0; } num *= flg; return 1;}int nume(int j, int k){ return Dp[j] + sum[j] * sum[j] - Dp[k] - sum[k] * sum[k];}int deno(int j, int k){ return 2 * (sum[j] - sum[k]);}int Get_Dp(int i, int j){return Dp[j] + M + (sum[i] - sum[j]) * (sum[i] - sum[j]);}int main(){ while(getint(N) && getint(M)){ //Dp[0] = sum[0] = 0; for(int i = 1; i <= N; ++ i) getint(sum[i]), sum[i] += sum[i - 1]; int fro = 1, bac = 0; Q[++ bac] = 0; for(int i = 1; i <= N; ++ i){ while(fro < bac && nume(Q[fro+1], Q[fro]) < sum[i] * deno(Q[fro+1], Q[fro])) ++ fro; Dp[i] = Get_Dp(i, Q[fro]); while(fro < bac && nume(i, Q[bac]) * deno(Q[bac], Q[bac-1]) <= nume(Q[bac], Q[bac-1]) * deno(i, Q[bac])) //while(fro < bac && nume(i, Q[bac-1]) * deno(Q[bac], Q[bac-1]) <= nume(Q[bac], Q[bac-1]) * deno(i, Q[bac-1])) -- bac; Q[++ bac] = i; //判断进队的时候必须有"="号,假设现在有i和j的斜率与j和k斜率相等,我们必须把j删除,因为可能在k之前还有点p,使得k也可以被删除,而删除掉j并不会使答案变坏。 //以上这种判断出队的方法是建立在图像的基础上的,目的是维护一个下凸包,所以将g[i ,j]与g[j, k]比较 //而建立在g[i,j]的定义上,还可以写成另一种,因为目的是维护下凸,所以只是要判断当i进入队列后,队尾的值是不是最优的(即下凸) //那么完全可以直接比较g[i, j]和g[i, j-1]的斜率,这样更直观,也是正确的,但同样存在"="的问题。可以写成上方注释掉的代码。 } printf("%d\n", Dp[N]); } return 0;}
- HDU3507--Print Article(斜率优化DP)
- [HDU3507]Print Article(斜率优化dp)
- hdu3507 Print Article(斜率优化dp)
- hdu3507 Print Article(斜率优化dp)
- hdu3507 Print Article DP+斜率优化
- 【HDU3507】Print Article-DP斜率优化入门
- [hdu3507] Print Article DP斜率优化入门
- 【HDU3507】【斜率优化DP】Print Article题解
- #HDU3507#Print Article(DP+斜率优化)
- [hdu3507] Print Article(斜率优化dp)
- HDU3507 Print Article 【斜率优化DP】
- HDU3507 print article【斜率优化dp】
- hdu3507 Print Article 斜率优化dp
- hdu3507(print article)- 线性dp+斜率优化
- HDU3507 Print Article —斜率优化dp典型题
- hdu3507 Print Article 单调队列斜率优化DP
- HDU3507 Print Article (斜率优化DP基础复习)
- 斜率优化DP模板题--HDU3507 Print Article
- Unity 理解刚体(Rigidbody)和碰撞体(Collider)和触发器(Is Trigger)以及刚体休眠(Rigidbody Sleeping)
- redis: jedis API使用及工具类
- Mysql数据库优化配置文件my.ini文件配置解释
- extern "C"
- MySQL索引工作原理
- #HDU3507#Print Article(DP+斜率优化)
- 浮点数
- mysql主从搭建
- JUnit自动化单元测试(四):@RunWith测试套件运行器的使用
- C#提示未能正确加载程序集或它的某一个依赖项
- Torch学习笔记(二):相关的环境配置
- Android Studio添加忽略文件
- 基于proteus的51单片机仿真实例六十八、8位数据锁存器74HC573应用实例
- ionic 微信分享只显示默认图片问题