斜率优化DP 与数形结合思想
2017-06-05 20:18
281 查看
前言
最近才入了DP优化的大坑……发现斜率优化DP还是很有用的
下面会结合一道例题,同时讲解斜率优化DP
正文
先看一下例题:HDU3507题目大意:有一串数列,要把它分割成若干段
每一段的代价是 这一段所有数的和 的平方 再加上常数M
求最小的代价和。
DP很好推啊,f[i]表示前i个数字的最小代价和
f[i]=Min{f[j]+(s[i]−s[j])2}+M
其中s[]是原数列的前缀和
按如下方式转化:
f[i]=Min{f[j]+s[i]2−2s[i]s[j]+s[j]2}+M
f[i]=Min{f[j]−2s[i]s[j]+s[j]2}+M+s[i]2
设k=2s[i],x=s[j],y=f[j]+s[j]2
由于Min{}外面的部分只与i有关,可以先不考虑
设里面的部分为b,则有:
b=−kx+y
y=kx+b
你会发现,这不就是一条直线嘛
我们来好好思考一下这条直线与DP之间的联系:
前面已求得的每个状态j都被抽象成二维平面上的一个点(x,y)
b是我们要求的最小值,而斜率k只与i有关
也就是说,要过所有的点做一条斜率为k的直线,
所有直线截距的最小值就是我们的b
如下图:
不难发现,能取到最小截距的状态j(x,y)一定在当前的 下凸壳 上
再加上s[j]随j递增(即x坐标递增)
我们就可以用凸包算法Andrew动态维护一个下凸壳
本题又有一个很好的性质,就是斜率k也是递增的
这导致了每次选取的状态j也是递增的
那么就可以用一个指针记录上次选取的状态,每次往后找即可
时间复杂度O(n)
扩展讨论
上述问题中,如果斜率k不递增,那就只能在凸壳上二分了:通过判断 mid左右两侧直线的斜率 与k的大小关系 来缩小范围
时间复杂度O(nlogn)
如果题目再恶心一点,连新加入点的x都不递增呢?
那就需要写一个Splay维护凸壳,或者CDQ分治
时间复杂度O(nlogn)
示例程序
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int maxn=500005; int n,m; LL s[maxn],f[maxn]; #define nc getchar inline int red(){ int tot=0,f=1;char ch=nc(); while (ch<'0'||'9'<ch) {if (ch=='-') f=-f;ch=nc();} while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=nc(); return tot*f; } struct point{ LL x,y; point() {} point(LL a,LL b):x(a),y(b) {} point operator-(const point&b) {return point(x-b.x,y-b.y);} }stk[maxn]; typedef point vec; LL cross(vec a,vec b){ return a.x*b.y-b.x*a.y; } LL getb(point a,LL k){ return -a.x*k+a.y; } int main(){ while (scanf("%d%d",&n,&m)==2){ for (int i=1;i<=n;i++) s[i]=s[i-1]+red(); memset(f,63,sizeof(f)); f[0]=0; int len=1,now=1;stk[1]=point(0,0); for (int i=1;i<=n;i++){ LL k=2*s[i]; while (now<len&&getb(stk[now+1],k)<getb(stk[now],k)) now++; f[i]=getb(stk[now],k)+m+s[i]*s[i]; point a(s[i],f[i]+s[i]*s[i]); while (len>1&&cross(stk[len]-stk[len-1],a-stk[len-1])<=0){ len--;if (now>len) now--; } stk[++len]=a; } printf("%lld\n",f ); } return 0; }
总结
斜率优化DP的存在,再一次提醒我们数形结合的重要性在OI中,类似的例子还有很多……
但是,在运用数形结合思想时,要注意“形”与“数”之间的联系
切勿将想法匆匆过一遍就用代码实现,容易搞混
相关文章推荐
- HDU3045 Picnic Cows (斜率DP优化)(数形结合)
- 斜率优化,数形结合(Average,uva 1451)
- UVA 1451 Average平均值 (数形结合,斜率优化)
- UVaLive LA 4726 UVa 1451 - Average (子序列最大平均数 数形结合 斜率优化 单调队列)
- [BZOJ3437]小P的牧场(斜率优化dp)
- [BZOJ3675][Apio2014]序列分割(斜率优化DP)
- BZOJ 1010: [HNOI2008]玩具装箱toy(dp+斜率优化)
- bzoj4518 [Sdoi2016]征途(斜率优化DP)
- [DP 斜率优化 CDQ分治||动态维护凸包] BZOJ 1492 [NOI2007]货币兑换Cash
- BZOJ1096: [ZJOI2007]仓库建设 斜率优化DP
- hdu3045 Picnic Cows(斜率优化DP)
- 队列优化和斜率优化的dp
- HDU-3045 Picnic Cows 斜率优化DP
- dp斜率优化 Pearls(Hdu1300)题解
- 【斜率优化DP】BZOJ1597 [Usaco2008 Mar]土地购买
- DP:斜率优化 Slope optimization
- dp斜率优化 hdu 2829 Lawrence 题解
- BZOJ 1010 [HNOI2008]玩具装箱toy 斜率优化DP
- [斜率优化的dp]storage题解
- poj 1260 Pearls 斜率优化dp