HDU 3507 Print Article (斜率优化DP)

来源:互联网 发布:淘宝抠图兼职怎么找 编辑:程序博客网 时间:2024/05/18 20:51

Print Article

Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 13922    Accepted Submission(s): 4317


Problem Description
Zero has an old printer that doesn't work well sometimes. As it is antique, he still like to use it to print articles. But it is too old to work for a long time and it will certainly wear and tear, so Zero use a cost to evaluate this degree.
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.
 

Input
There are many test cases. For each test case, There are two numbers N and M in the first line (0 ≤ n ≤ 500000, 0 ≤ M ≤ 1000). Then, there are N numbers in the next 2 to N + 1 lines. Input are terminated by EOF.
 

Output
A single number, meaning the mininum cost to print the article.
 

Sample Input
5 559575
 

Sample Output
230
 

Author
Xnozero
 

Source
2010 ACM-ICPC Multi-University Training Contest(7)——Host by HIT

刷bzoj看到1010,怎么都不会做,搜题解说是斜率DP,果断去看斜率DP,就发现了这个模板题,此题的题解都千篇一律有没有,我也想有点创新,但感觉不能破坏传统不是,我也就跟着写了写。

所谓的斜率DP,就是DP的递推式可以转换成类似斜率的形式,怎么可能转换成斜率的形式呢?首先,此递推式肯定有特点,就是确保当前DP[i]是最优解,他是由DP[j]经过公式递推得到,类似于这样dp[i]= min{ dp[j]+(sum[i]-sum[j])^2 +M }  0<j<i ,显然,DP[i]可以有DP[j]直接得到,而且是某个DP[j]得到,直接运算的话需要两层循环,非常容易超时,这里就需要利用斜率优化DP了,将N^2的时间复杂度直接降到N,神奇。

此题可以假设存在k<j<i,且K时决策不如J时优,则将k和j带入上面的DP的递推式,中间用<连接,然后不断化简,得到(dp[j]+num[j]^2-(dp[k]+num[k]^2))/(2*(num[j]-num[k]))<sum[i] ,分子有关j的项看成yj,有关K的看成yk,分母看作xj,xk,则得到(yj-yk)/(xj-xk)<sum[i],熟悉吧,斜率就这么出来了,然后经过一系列验证,得到如果是最优解的话需要从左到右斜率逐渐降低。数组模拟单调队列,类似于凸包算法啊!遇到斜率大的就可以出队列,最后计算当前最优的DP[i],最后输出DP【n】。

这波解释完美。

代码实现:

#include<iostream>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#include<cstdio>#define ll long long#define mset(a,x) memset(a,x,sizeof(a))using namespace std;const double PI=acos(-1);const int inf=0x3f3f3f3f;const double esp=1e-6;const int maxn=5e5+5;const int mod=1e9+7;int dir[4][2]={0,1,1,0,0,-1,-1,0};ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}ll lcm(ll a,ll b){return a/gcd(a,b)*b;}ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}int map[maxn],dp[maxn],q[maxn];int head,tail,n,m;int DP(int i,int j){return dp[j]+m+(map[i]-map[j])*(map[i]-map[j]);}int UP(int j,int k){return dp[j]+map[j]*map[j]-(dp[k]+map[k]*map[k]);}int DOWN(int j,int  k){    return 2*(map[j]-map[k]);}int main(){int i,j,k;while(cin>>n>>m){mset(dp,0);mset(q,0); for(i=1;i<=n;i++)cin>>map[i];map[0]=dp[0];for(i=1;i<=n;i++){map[i]+=map[i-1];}head=tail=0;q[tail++]=0;for(i=1;i<=n;i++){while(head+1<tail&&UP(q[head+1],q[head])<=DOWN(q[head+1],q[head])*map[i])head++;dp[i]=DP(i,q[head]);while(head+1<tail&&UP(i,q[tail-1])*DOWN(q[tail-1],q[tail-2])<=UP(q[tail-1],q[tail-2])*DOWN(i,q[tail-1]))            tail--;                        q[tail++]=i;}cout<<dp[n]<<endl;}return 0;}



(sum[i]sum[j]L)2(sum
原创粉丝点击