hdu 3507 Print Article(斜率优化DP)

本文针对HDU3507题目进行解析,采用动态规划与斜率优化相结合的方法,通过单调队列实现O(n)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:hdu 3507 Print Article

题意:

每个字有一个值,现在让你分成k段打印,每段打印需要消耗的值用那个公式计算,现在让你求最小值

题解:

设dp[i]表示前i个字符需要消耗的最小值,那么有dp[i]=min{dp[k]+(sum[i]-sum[k])2+m)}(k<i)。

这样是n2 的做法。

考虑用斜率优化:

设k<j,对于dp[i],从k+1到i为一段比j+1到i为一段更优。

那么有

dp[j]+(sum[i]-sum[j])2+m<=dp[k]+(sum[i]-sum[k])2+m

整理得:

dp[j]+sum[j]*sum[j]-(dp[k]+sum[k]*sum[k])/sum[j]-sum[k]<=2*sum[i]。

不等式的右边就是一个斜率,然后用单调队列优化,做到O(n)的复杂度。

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;++i)
 3 using namespace std;
 4 
 5 const int N=5e6+7;
 6 int n,m,dp[N],sum[N],Q[N],head,tail;
 7 
 8 int getx(int j,int k){return sum[j]-sum[k];}
 9 int gety(int j,int k){return dp[j]+sum[j]*sum[j]-dp[k]-sum[k]*sum[k];}
10 int check(int i,int j,int k){return gety(i,j)*getx(j,k)<=gety(j,k)*getx(i,j);}
11 
12 int main()
13 {
14     while(~scanf("%d%d",&n,&m))
15     {
16         F(i,1,n)scanf("%d",sum+i),sum[i]+=sum[i-1];
17         head=1,tail=0;
18         Q[++tail]=0;
19         F(i,1,n)
20         {
21             while(head<tail&&gety(Q[head+1],Q[head])<=2*sum[i]*getx(Q[head+1],Q[head]))head++;
22             dp[i]=dp[Q[head]]+(sum[i]-sum[Q[head]])*(sum[i]-sum[Q[head]])+m;
23             while(head<tail&&check(i,Q[tail],Q[tail-1]))tail--;
24             Q[++tail]=i;
25         }
26         printf("%d\n",dp[n]);
27     }
28     return 0;
29 }
View Code

 

转载于:https://www.cnblogs.com/bin-gege/p/6150146.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值