AtCoder Beginner Contest 158 F - Removing Robots题解(dp)

题目链接

题目大意

N个机器人,第i个机器人在Xi位置上,若一个机器人被激活,则它将向右移动Di。

若途径别的机器人,则该机器人也将被激活,求可以得到多少个没被激活的机器人的集合(激活次数不限)(对998244353取模)

注意途径的机器人被激活的条件是距离和他必须要小于(或间接小于)di。等于不行

题目思路

肯定首先要按照机器人的位置升序排序。然后逆向dp

令dp[x]代表x~n的集合数,当第x个机器人不激活时,那么就是dp[x+1];当第x个机器人被激活时,那么就是dp[next].

next代表离x最近的不被x影响(包括间接)的机器人。

pos里面的first和second分别代表起点i和从i开始最近不被影响的机器人。

本来想用二分判断next的值,但是其实可以直接用堆栈,因为其实元素直接是相互有关联的。

而且每一个元素都是最多入栈和出栈一次时间复杂度为0(n)

代码

#include<cstdio>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn=2e5+5;
const int mod=998244353;
int n,dp[maxn];
pair<int,int> a[maxn];
stack < pair<int,int> > pos;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d %d",&a[i].first,&a[i].second);
    }
    sort(a+1,a+1+n);
    dp[n+1]=1;//初始化
    for(int i=n;i>=1;i--){
        int t=a[i].first+a[i].second,next=i+1;
        while(!pos.empty()&&t>a[pos.top().first].first){//注意没有等于号,而且是while循环
            next=pos.top().second;
            pos.pop();
        }
        pos.push({i,next});
        dp[i]=(dp[i+1]+dp[next])%mod;//选和不选
    }
    printf("%d\n",dp[1]);
    return 0;
}

发布了68 篇原创文章 · 获赞 2 · 访问量 2257

猜你喜欢

转载自blog.csdn.net/m0_46209312/article/details/105070756
今日推荐