題目鏈接
大意:給你n個機器人,每個機器人在,位置,如果被激活了就會移動到,然後被銷燬,中途遇到的機器人都會被激活且移動。
有一種操作是:選擇一個未被激活的機器人並激活它。
你可以執行任意次數操作(還有未激活的)
問最終會有多少種不同的全都沒被激活機器人集合。
思路:顯然先把每個機器人激活後到能影響的最遠的機器人編號預處理出來。然後分兩種情況進行dp即可。
預處理的處理方式大致上:
先把所有機器人按照座標排序。從大到小遍歷,然後二分出當前機器人的最大包含的機器人,那麼,特別的如果那麼。
直接用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;
}