CF732D

今上午的模拟赛考了这道题,改了一下题面。

本来切掉了,考场源码交到 CF 上也过了,但是因为你教师机评测太牛逼硬是把我代码判错了,现在也不是很理解为什么。


用了一种和大多数人不一样的方法。

首先考虑什么时候无解。

显然,越晚攻击一个敌人,就越有可能击败他。也就是说,如果我们让所有敌人在最后出现时刻时被攻击,仍不能击败所有人,那么无解。

然后我们再考虑如何取最优答案。

让所有人在最后时刻被击败肯定是最劣的一种答案,那么想要使答案尽可能优,肯定要每次找出最后一个被消灭的敌人,使他的出现时刻变成上一个,再尝试能否全部击败。

接着考虑一下,移动一个敌人会产生什么影响。

我们先记录最劣情况下到每个时刻的士兵数量。

假设我们最后出现的敌人位置为 (x),这个敌人的上一个出现位置是 (y),消灭这个敌人需要花费 (v) 的士兵。

那么我们把这个士兵从 (x) 移走,显然 ([x,n]) 位置的士兵数要在现在的基础上加 (v+1) 个(攻击花费的 (v) 个与走到 (x) 位置时新增的 (1) 个)。

然后我们把这个士兵插入到位置 (y),那么 ([y,n]) 的士兵数要在现在的基础上减去 (v+1) 个,理由同上。

如何判断移动这个士兵合不合法呢?只需要判断减去这个值之后,([y,n]) 位置有没有出现负数即可,原因显然。具体操作时可以求出 ([y,n]) 位置的最小值,判断一下是否大于等于 (v+1)

所以我们只需要对序列进行区间加和区间求最小值两种操作,上线段树即可。

bool vis[maxn];
int n,m,tot,Ans,all,a[maxn];
int lst[maxn],ck[maxn];
int pos[maxn],val[maxn];
deque<int> id[maxn];
struct node{int a,b;};
deque<node> q;

namespace Seg{
  #define ls x<<1
  #define rs x<<1|1
  int minx[maxn<<2],lazy[maxn<<2];
  
  void pushup(int x){
    minx[x]=min(minx[ls],minx[rs]);
  }
  
  void pushdown(int x){
    if(lazy[x]==0) return;
    lazy[ls]+=lazy[x];lazy[rs]+=lazy[x];
    minx[ls]+=lazy[x];minx[rs]+=lazy[x];
    lazy[x]=0;
  }
  
  void build(int x,int l,int r){
    if(l==r){
      minx[x]=a[l];
      return;
    }
    int mid=l+r>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    pushup(x);
  }
  
  void update1(int x,int l,int r,int L,int R,int val){
    if(L<=l&&R>=r){
      minx[x]+=val;
      lazy[x]+=val;
      return;
    }
    int mid=l+r>>1;pushdown(x);
    if(L<=mid) update1(ls,l,mid,L,R,val);
    if(R>=mid+1) update1(rs,mid+1,r,L,R,val);
    pushup(x);
  }
  
  int query(int x,int l,int r,int L,int R){
    if(L<=l&&R>=r) return minx[x];
    int mid=l+r>>1,ans=INF;pushdown(x);
    if(L<=mid) ans=min(ans,query(ls,l,mid,L,R));
    if(R>=mid+1) ans=min(ans,query(rs,mid+1,r,L,R));
    return ans;
  }
}

signed main(){
  n=read(); m=read();
  for(int i=1;i<=n;i++){
    pos[i]=read();
    if(pos[i]){
      id[pos[i]].push_front(i);
      q.push_front((node){i,pos[i]});
    }
  }
  for(int i=n;i>=1;i--){
    if(!vis[pos[i]]||!pos[i]){
      vis[pos[i]]=1;
      if(pos[i]) lst[i]=pos[i],id[pos[i]].pop_front(),Ans=max(Ans,i);
    }
    else lst[i]=0;  
  }
  for(int i=1;i<=m;i++) val[i]=read();
  for(int i=1;i<=n;i++){
    if(lst[i]){
      all++;
      tot-=val[lst[i]];
      if(tot<0) return puts("-1"),0; 
    }
    else tot++;
    a[i]=tot;
  }
  if(all<m) return puts("-1"),0;
  Seg::build(1,1,n);
  while(1){
    if(q.size()==m) break;
    node P=q.front();q.pop_front();
    
    int fir=P.a,sec=P.b;
    int nxt_pos=id[sec].front();  
    
    id[sec].pop_front();
    Seg::update1(1,1,n,fir,n,1+val[sec]);
    int minx=Seg::query(1,1,n,nxt_pos,n);
    
    if(minx<1+val[sec]||minx>=INF) return printf("%d
",Ans),0;
    Seg::update1(1,1,n,nxt_pos,n,-1-val[sec]);Ans=q.front().a;
  }
  printf("%d
",Ans);
  return 0;
}
原文地址:https://www.cnblogs.com/KnightL/p/15480864.html