zoukankan      html  css  js  c++  java
  • [BZOJ] 1597: [Usaco2008 Mar]土地购买

    记一次(O(nlogn))吊锤(O(n))实录

    (f[i])表示前(i)块土地,第(i)块必选的最小代价

    为了方便转移,按(h)为第一关键字递减,(w)为第二关键字递增排序,就有

    [f[i]=min_{j=1}^{i-1}{f[j]+cost[j+1][i]} ]

    其中

    [cost[i][j]=h[i]*max_{k=i}^j{w[k]} ]

    状态是(O(n))的,转移可以用ST表优化到(O(n))

    这时候我们就得到了一个(O(n^2))的优秀TLE解法

    实际上这里不需要ST表,对于一块土地,如果有另一块土地,比它长,还比它宽,那它就可以在买那个土地时顺便买走

    所以,最终的土地序列是(h)递减,(w)递增的

    因此可以改写一下DP式

    [f[i]=min_{j=1}^{i-1}{f[j]+h[j+1] imes w[i]} ]

    (cost[i][j]=w[i] imes h[j+1])

    [egin{align} cost[i][j]+cost[i+1][j+1]=w[i] imes h[j+1]+w[i+1] imes h[j+2]\ cost[i+1][j]+cost[i][j+1]=w[i+1] imes h[j+1]+w[i] imes h[j+2] end{align} ]

    (1)式减(2)式得

    [LHS=cost[i][j]+cost[i+1][j+1]-cost[i+1][j]-cost[i][j+1] ]

    [egin{align*} RHS&=w[i] imes (h[j+1]-h[j+2])+w[i+1] imes(h[j+2]-h[j+1])\ &=(h[j+1]-h[j+2]) imes (w[i]-w[i+1]) end{align*} ]

    由于h递减,w递增

    [egin{align*} h[j+1]-h[j+2]>0\ w[i]-w[i+1]<0 end{align*} ]

    因此

    [RHS<0 ]

    所以

    [cost[i][j]+cost[i+1][j+1]<cost[i][j+1]+cost[i+1][j] ]

    至此,我们严格证明了(cost)是一个凸函数,所以该DP式满足决策单调性

    我们可以用单调队列维护,复杂度(O(nlogn))

    (不知道为什么甚至用了deque,跑得比大部分(O(n))的斜率优化还快)

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<bitset>
    #include<deque>
    using namespace std;
    
    inline int rd(){
      int ret=0,f=1;char c;
      while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
      while(isdigit(c))ret=ret*10+c-'0',c=getchar();
      return ret*f;
    }
    
    const int MAXN = 50005;
    
    inline void upmax(int &x,int y){x=max(x,y);}
    inline void upmin(int &x,int y){x=min(x,y);}
    
    int n;
    typedef long long ll;
    
    struct Node{
      int x,y;
      bool operator <(const Node &rhs)const{
        return x==rhs.x?y>rhs.y:x>rhs.x;
      }
    }tmp[MAXN],node[MAXN];
    int tot;
    
    struct Que{
      int l,r,p;
      Que(int _p,int _l,int _r){l=_l;r=_r;p=_p;}
    };
    
    deque<Que> Q;
    ll f[MAXN];
    
    ll calc(int p,int x){
      return f[p]+1ll*node[p+1].x*node[x].y;
    }
    
    int fnd(int x){
      int l=Q.back().l,r=Q.back().r,p=Q.back().p,ret;
      while(l<r){
        int mid=(l+r)>>1;
        if(calc(x,mid)<=calc(p,mid))r=mid;
        else ret=mid,l=mid+1;
      }
      return ret+1;
    }
    
    signed main(){
      memset(f,0x7f,sizeof(f));
      f[0]=0;
      n=rd();
      for(int i=1;i<=n;i++)tmp[i].x=rd(),tmp[i].y=rd();
      sort(tmp+1,tmp+1+n);
      for(int i=1;i<=n;i++){
        if(tot&&node[tot].y>=tmp[i].y)continue;
        node[++tot]=tmp[i];
      }
      Q.push_back(Que(0,1,tot));
      for(int i=1;i<=tot;i++){
        while(!Q.empty()&&Q.front().r<i)Q.pop_front();
        f[i]=calc(Q.front().p,i);//f[i]=f[p]+cost[p+1][i]
        if(calc(i,tot)>calc(Q.back().p,tot))continue;
        while(!Q.empty()&&calc(i,Q.back().l)<calc(Q.back().p,Q.back().l))Q.pop_back();
        if(Q.empty()){Q.push_back(Que(i,i+1,tot));continue;}
        int pos=fnd(i);
        Q.back().r=pos-1;Q.push_back(Que(i,pos,tot));
      }
      cout<<f[tot];
      return 0;
    }
    
    未经许可,禁止搬运。
  • 相关阅读:
    alpha 冲刺 —— 十分之一
    福大软工 · 第七次作业
    福大软工 · 第八次作业(课堂实战)- 项目UML设计(团队)
    2018软工实践——团队答辩
    福大软工1816 · 第五次作业
    福大软工1816 · 第四次作业
    软工实践第四次作业--结队的第一次合作
    软工实践第二次作业--思索
    华中农业大学第五届程序设计大赛网络同步赛解题报告2(转)
    华中农业大学第五届程序设计大赛网络同步赛解题报告(转)
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9811193.html
Copyright © 2011-2022 走看看