[DP优化] POJ 1160 Post Office

来源:互联网 发布:java字符数组赋值 编辑:程序博客网 时间:2024/06/06 05:27

另解:四边形不等式优化

考虑这个最优解关于段数是凸的,那么我们不限制段数,而是给每段一个额外的权值,随着这个权值单调变化,最优解的段数也会单调变化,二分出最优解是 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[N],X; int pre[N];int w[N][N],a[N];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[N]; 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[n]-MID*m;    }  }  printf("%lld\n",ans);  return 0;}
原创粉丝点击