zoukankan      html  css  js  c++  java
  • FZU2279 : Cantonese

    首先把相同的事件点合并,那么每个点有时间$t_i$,位置$x_i$,价值$v_i$。

    考虑DP,设$f_i$表示按时间从小到大考虑每个事件,目前位于事件$i$的时间与位置时,最多能让多少个事件发生。在$t_i$秒初对方不能碰到$i$,但在这一秒结束结算时,对方可以碰到$i$。

    则$f_i=max(f_j)+v_i$。

    其中,$j$需要满足一系列条件:

    $1.j$要能在规定时间内到达$i$,也就是$t_i-t_jgeq|x_i-x_j|$。

    将绝对值拆掉并移项,得:

    $t_i-x_igeq t_j-x_j(1)$

    $t_i+x_igeq t_j+x_j(2)$

    $2.$在$t_i$秒初对方不能碰到$i$:

    设$s_i$表示前$i$秒存在的事件数,那么在第$t_i$秒初,也就是第$t_i-1$秒末,对方一共前进了$s_{t_i-1}-f_j$步,所以$s_{t_i-1}-f_j<x_i$,即$f_j>s_{t_i-1}-x_i(3)$。

    $3.j$在移动到$i$的过程中不能被对方追上:

    最坏情况下,一定是$j$在$t_j$时刻位于$x_j$,然后一直向右移动,那么在第$p(t_jleq p<t_i)$秒末,对方位于$s_p-f_j$,$j$位于$x_j-t_j+p$,需要满足:

    $s_p-f_j<x_j-t_j+p$

    移项得:

    $s_p-p<x_j-t_j+f_j$

    即$max(s_p-p)<x_j-t_j+f_j$

    对$s_p-p$建线段树维护区间最大值,然后在线段树上二分即可得到最大的$o$,满足$[t_j,o)$都不会被追上,设$lim_j=o$,则$lim_jgeq t_i(4)$。

    对于限制$(3)$,只需要求出最大的$f_j$,然后判断是否可行即可。

    对于限制$(1)$,可以通过排序解决。

    对于限制$(2)$和$(4)$,可以cdq分治后扫描线+树状数组处理。

    时间复杂度$O(nlog^2n)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=100010,M=262150,inf=10000000;
    int Case,_,n,m,cnt,i,j,ans;
    int pt[N],post[N],s[N],w[N],val[N],lim[N],f[N];
    int qa[N],qb[N],ca,cb;
    int FLAG,bit[N],vis[N];
    int mx[M],O,OFFSET;
    struct P{int t,x,v;P(){}P(int _t,int _x,int _v){t=_t,x=_x,v=_v;}}a[N],b[N];
    inline bool cmpa(const P&a,const P&b){return a.t==b.t?a.x<b.x:a.t<b.t;}
    inline bool cmpb(const P&a,const P&b){
      if(a.t-a.x!=b.t-b.x)return a.t-a.x<b.t-b.x;
      return a.t+a.x<b.t+b.x;
    }
    inline bool cmpq(int x,int y){
      return val[x]<val[y];
    }
    inline int lower(int x){
      int l=1,r=m,mid,t;
      while(l<=r)if(pt[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1;
      return t;
    }
    inline void up(int&x,int y){x<y?(x=y):0;}
    inline void add(int x,int p){for(;x<=m;x+=x&-x)if(vis[x]<FLAG)vis[x]=FLAG,bit[x]=p;else up(bit[x],p);}
    inline void ask(int&t,int x){for(;x;x-=x&-x)if(vis[x]==FLAG)up(t,bit[x]);}
    void build(int x,int a,int b){
      if(a==b){
        mx[x]=w[a];
        return;
      }
      int mid=(a+b)>>1;
      build(x<<1,a,mid);
      build(x<<1|1,mid+1,b);
      mx[x]=max(mx[x<<1],mx[x<<1|1]);
    }
    void getr(int x,int a,int b,int c){
      if(c<=a){
        if(mx[x]<OFFSET)return;
        if(a==b){
          O=a;
          return;
        }
      }
      int mid=(a+b)>>1;
      if(c<=mid){
        getr(x<<1,a,mid,c);
        if(O)return;
      }
      getr(x<<1|1,mid+1,b,c);
    }
    inline void getlim(int x){
      int offset=b[x].x+f[x]-b[x].t;
      lim[x]=0;
      int t=post[x];
      if(w[t]>=offset)return;
      O=0;
      OFFSET=offset;
      getr(1,1,m,t);
      if(!O)O=m;
      lim[x]=O;
    }
    void CDQ(int l,int r){
      if(l==r){
        if(b[l].t==0)up(f[l],0);
        if(f[l]<=s[post[l]-1]-b[l].x)f[l]=-inf;
        if(f[l]>=0){
          f[l]+=b[l].v;
          up(ans,f[l]);
          getlim(l);
        }
        return;
      }
      int mid=(l+r)>>1;
      CDQ(l,mid);
      int i,j;
      ca=cb=0;
      for(i=l;i<=mid;i++)if(f[i]>=0&&lim[i])qa[++ca]=i;
      for(i=r;i>mid;i--)qb[++cb]=i;
      sort(qa+1,qa+ca+1,cmpq);
      sort(qb+1,qb+cb+1,cmpq);
      FLAG++;
      for(i=j=1;i<=cb;i++){
        while(j<=ca&&val[qa[j]]<=val[qb[i]]){
          add(m-lim[qa[j]]+1,f[qa[j]]);
          j++;
        }
        ask(f[qb[i]],m-post[qb[i]]+1);
      }
      CDQ(mid+1,r);
    }
    inline void solve(){
      sort(a+1,a+m+1,cmpa);
      for(cnt=0,i=1;i<=m;i=j){
        for(j=i;j<=m&&a[i].t==a[j].t&&a[i].x==a[j].x;j++);
        b[++cnt]=P(a[i].t,a[i].x,j-i);
        if(b[cnt].t==0)b[cnt].v=0;
      }
      sort(b+1,b+cnt+1,cmpb);
      for(i=1;i<=cnt;i++)pt[i]=b[i].t;
      sort(pt+1,pt+cnt+1);
      for(m=0,i=1;i<=cnt;i++)if(i==1||pt[i]>pt[i-1])pt[++m]=pt[i];
      for(i=1;i<=cnt;i++)post[i]=lower(b[i].t);
      for(i=1;i<=m;i++)s[i]=0;
      for(i=1;i<=cnt;i++)s[post[i]]+=b[i].v;
      for(i=1;i<=m;i++)s[i]+=s[i-1];
      for(i=1;i<=m;i++)w[i]=s[i]-pt[i];
      for(i=1;i<=cnt;i++)f[i]=-inf,val[i]=b[i].t+b[i].x;
      build(1,1,m);
      CDQ(1,cnt);
    }
    int main(){
      scanf("%d",&Case);
      for(_=1;_<=Case;_++){
        scanf("%d%d",&n,&m);
        for(i=1;i<=m;i++)scanf("%d%d",&a[i].t,&a[i].x);
        a[++m]=P(0,1,0);
        ans=0;
        if(m)solve();
        printf("Case #%d: %d
    ",_,ans);
      }
    }
    

      

  • 相关阅读:
    redis发布订阅
    CSS 布局
    CSS 布局
    CSS Float(浮动)实例
    CSS 布局
    CSS Float(浮动)
    CSS Position(定位)实例
    CSS Position(定位)
    CSS Display(显示) 与 Visibility(可见性)实例
    CSS Display(显示) 与 Visibility(可见性)
  • 原文地址:https://www.cnblogs.com/clrs97/p/7226848.html
Copyright © 2011-2022 走看看