AtCoder Beginner Contest 158 F.Removing Robots

題目鏈接
大意:給你n個機器人,每個機器人在xix_i,位置,如果被激活了就會移動到xi+di1x_i+d_i-1,然後被銷燬,中途遇到的機器人都會被激活且移動。
有一種操作是:選擇一個未被激活的機器人並激活它。
你可以執行任意次數操作(還有未激活的)
問最終會有多少種不同的全都沒被激活機器人集合。
思路:顯然先把每個機器人ii激活後到能影響的最遠的機器人編號LiL_i預處理出來。然後分兩種情況進行dp即可。
預處理的處理方式大致上:
先把所有機器人按照座標排序。從大到小遍歷,然後二分出當前機器人的xi+di1x_i+d_i-1最大包含的機器人yy,那麼Li=maxj=i+1yLjL_i=max_{j=i+1}^y L_j,特別的如果y=iy=i那麼Li=iL_i=i
直接用bit維護一下後綴最大值即可。
剩下的dp部分就很顯然了。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
int n;
struct uzi{
  int a,b,i;
  bool operator <(const uzi &t)const{
    return a<t.a;
  }
}p[N];
int L[N];
LL f[N];
const LL mod=998244353;
int t[N];
void add(int p,int d){
  for(;p<N;p+=p&-p)t[p]=max(t[p],d);
}
int ge(int p,int d){
  int res=0;
  for(;p;p-=p&-p)res=max(res,t[p]);
  return res;
}
int main() {
  ios::sync_with_stdio(false);
  cin>>n;
  for(int i=1;i<=n;i++)cin>>p[i].a>>p[i].b,p[i].i=i;
  sort(p+1,p+1+n);
  auto get=[&](int x){
    int l=1,r=n,ans=1;
    while(l<=r){
      int mid=l+r>>1;
      if(p[mid].a<=x)ans=mid,l=mid+1;
      else r=mid-1;
    }
    return ans;
  };
  for(int i=n;i>=1;i--){
    L[i]=i;
    int x=get(p[i].a+p[i].b-1);
    L[i]=max(L[i],ge(x,1));
    add(i,L[i]);
  }
  f[1]=1;
  for(int i=1;i<=n;i++){
    f[i+1]+=f[i];//不開
    f[L[i]+1]+=f[i];//開
    f[i+1]%=mod;
    f[L[i]+1]%=mod;
  }
  cout<<f[n+1]<<endl;
  return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章