本题的朴素 dp 方程 :
表示前 个人,分了
段(分了
条船),上一段(上一条船)的结尾在
表示第 k+1 个到第 i 个人的沮丧值之和
//朴素 dp
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<i;k++)
{
f[i][j]=min(f[i][j],f[k][j-1]+calc(k+1,i));
}
时间复杂度为
-
优化
每次枚举决策点 都要从0 到 i-1 显然有很多冗余状态,如果能缩小
决策点
的取值范围就可以减少枚举的次数,进而降低时间复杂度
-
四边形不等式证明单调性
四边形不等式:对于
, 如果
![]()
那么方程就满足决策单调
若
就是两块蓝色的矩形
就是两块黄色的矩形
黄色部分比蓝色部分多了两块阴影面积的矩形
所以 ,符合四边形不等式,满足决策单调性
设 表示前
个人,分了
条船,
的最优决策点
得
-
时间复杂度
对于 的转移 ,转移的复杂度为
所有的转移复杂度之和为
,为
级别的
而 相当于矩形的对角线,一共有
条
因此总时间复杂度为 级别,已经可以AC本题了
memset(f,0x3f,sizeof(f));
n=read();m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) {
s[i][j]=read(); s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
for(int j=0;j<=m;j++)
f[0][j]=0,opt[n+1][j]=n-1;
for(int j=1;j<=m;j++)
for(int i=n;i>=1;i--)
for(int k=opt[i][j-1];k<=opt[i+1][j];k++)
if(f[i][j]>f[k][j-1]+calc(k+1,i))
{
opt[i][j]=k;
f[i][j]=f[k][j-1]+calc(k+1,i);
}
cout<<f[n][m];
以上就是利用四边形不等式优化 2D1D方程 的做法
2D1D:
个状态 ,
的状态计算复杂度的dp转移方程
-
四边形不等式优化1D1D方程
for(int i=1;i<=n;i++)
for(int j=0;j<i;j++)
f[i]=min(f[i],f[j]+calc(j+1,i));
此时,朴素的dp方程时间复杂度为
和 2D1D 方程一样,设 为
的最优决策点
设,对于
有 ,
因为 满足四边形不等式,那么
且
两式相减并移项,
那么,对于 ,决策点在任何
都没有
优秀
所以,对于 ,
这样就确定了枚举 决策点的下界,而上每次要枚举到
,复杂度仍然是
级别
例如:
就表示
的最优决策点在
, 即
是由
转移过来的
化一下储存方式,改成一个三元组的单调队列
该三元组 表示
到
最优决策点在
现有
二分求单调对列中第一个没有41优秀的位置并更新,时间复杂度为
比如这里101项是第一个可以被41更新的,那么就更新三元组队列(如图)
而当 大于比队首的
时,就踢掉队首