您的位置:首页 > 其它

[DP优化] POJ 1160 Post Office

2017-07-06 15:53 495 查看
另解:四边形不等式优化

考虑这个最优解关于段数是凸的,那么我们不限制段数,而是给每段一个额外的权值,随着这个权值单调变化,最优解的段数也会单调变化,二分出最优解是 m 段就好了

这个的本质是二分出那个凸函数在 m 上的斜率

然后这个dp是满足决策单调性的 复杂度O(nlog2n)

PS.之前一直有个坑是当三点共线也就是连续两段斜率一样时,二分不到中间那个点,这个其实需要一点小细节上的处理,感谢阿爷的帮助

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;

const int N=305;

int n,m;
ll f
,X; int pre
;
int w

,a
;

inline int ck(){
int p=n,ret=0;
while (p) p=pre[p],ret++;
return ret;
}

struct abcd{
int x,l,r;
abcd(int x=0,int l=0,int r=0):x(x),l(l),r(r) { }
bool operator < (const abcd &B) const{
return l<B.l;
}
}sta
; int pnt;

inline ll calc(int x,int y){
if (x>y) return 1LL<<60;
return f[x]+w[x+1][y]+X;
}

inline int Solve(ll X){
pnt=0; ::X=X;
sta[++pnt]=abcd(0,1,n);
for (int i=1;i<=n;i++){
int t=upper_bound(sta+1,sta+pnt+1,abcd(0,i,0))-sta-1;
f[i]=calc(sta[t].x,i); pre[i]=sta[t].x;
if (i==n) continue;
while (calc(sta[pnt].x,sta[pnt].l)>=calc(i,sta[pnt].l)) pnt--;
int L=sta[pnt].l,R=sta[pnt].r+1,MID;
while (L+1<R){
MID=(L+R)>>1;
if (calc(sta[pnt].x,MID)<calc(i,MID))
L=MID;
else
R=MID;
}
sta[pnt].r=R-1;
if (R<=n) sta[++pnt]=abcd(i,R,n);
}
return ck();
}

int main(){
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",a+i);
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++)
w[i][j]=w[i][j-1]+a[j]-a[(i+j)>>1];
ll L=0,R=1e9,MID; ll ans;
while (L+1<R){
int t=Solve(MID=(L+R)/2);
if (t<m){
R=MID;
}else{
L=MID;
ans=f
-MID*m;
}
}
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: