codeforces 474E 最长跳跃路线 简化版

本文探讨了一个关于木桩跳跃的算法问题,旨在找到能够跳过的最多木桩数量。通过将问题转化为最长不下降子序列模型,并利用线段树及离散化技巧,实现了高效的求解方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述
BSNY来到一个木桩阵,这个木桩阵是由n个木桩组成的,排成直线,每个木桩有个高度hi,BSNY可以从某个木桩开始,一直向后跳,但跳跃的位置是由限制的,如果BSNY现在在第i个木桩,想跳到第j个木桩,需要满足条件:i<j 同时 |hi-hj|>=d
现在BSNY希望能跳的木桩数量最多,问最多可以跳多少木桩?
样例输入
5 2
1 3 6 7 4
样例输出
4
【样例说明】
可以从1点开始,然后跳到第2个点,第3个点,第5个点,总共跳4个点
其他样例:
输入:
10 3
2 1 3 6 9 11 7 3 20 18
输出:
6
【数据规模和约定】
1<=n<=10^5  0<=d<=10^9

1<=hi<=10^9

******************************************

solution:相信大家都会写n^2的暴力吧?直接套个最长不下降的模型就行了。但我们再想想,这个条件到底能怎么转化?根据绝对值的知识,我们可以得到对于当前点j,它能跳过来的hi应满足条件hj+d<=hi或者hj-d>=hi,在这些范围里取某个i的最大值加上1并添加进去。这样一来,我们是不是又得到了一个可以基于木桩高度的线段树模型?但是随之而来的问题:hi最大有10^9,这样无疑空间会爆,怎样才能使得空间在规定范围内呢?这里就需要对高度进行离散化了,我们只保留h之间的高度关系,对于数值可以抽象保存。

例如第一个样例,经离散化后的h变为:

1 2 4 5 3

这样一来,hi最大只有n了。

但是,问题又来了,我们不是需要计算hj+d和hj-d吗?你h数组离散化之后,加减d时的数不就失真了吗?对此,我考虑了一会儿,其实我们可以对d进行二分,我们先用另外一个数组保存原始的h值,然后每次运算时对h+d和h-d进行二分查找,得到一个近似范围。比如还是那个样例,我第一个1+2=3,那么二分时我就可以得到2,1-2=-1,就是0。这个比那个离散化还要抽象,尤其是那个二分查找对上界和下界的讨论比较繁琐。希望读者好好揣摩一下。我的代码经过多次修改才AC,不大美观,希望老司机能提出修改意见。

#include<cstdio>
#include<iostream>
#include<algorithm>
#define p1 id<<1
#define p2 id<<1^1
using namespace std;
int n,m,ans;
int tree[400005],li[100005],f[100005];
int pre_do[100005];
struct ty
{int v,id;
}a[100005],b[100005];
bool cmp(ty x,ty y)
{
    if(x.v!=y.v) return x.v<y.v;
    return x.id<y.id;
}
int erfen1(int l,int r,int s)
{
    int mid=(l+r)/2;
    if(l>r) return r;
    if(s>=a[mid].v) return erfen1(mid+1,r,s);
    else return erfen1(l,mid-1,s);
}
int erfen2(int l,int r,int s)
{
    int mid=(l+r)/2;
    if(l>r) return l;
    if(s>a[mid].v) return erfen2(mid+1,r,s);
    else return erfen2(l,mid-1,s);
}
void lisanhua()
{
    li[1]=1;
    pre_do[a[1].id]=1;
    int k=1;
    for(int i=2;i<=n;i++)
    {
        if(a[i].v!=a[i-1].v) k++;
        li[i]=k;
        pre_do[a[i].id]=k;
    }
}
void update(int id,int l,int r,int x,int y)
{
    if(l==r&&l==x)
    {
        tree[id]=max(tree[id],y);
        return;
    }
    int mid=(l+r)/2;
    if(x<=mid) update(p1,l,mid,x,y); else update(p2,mid+1,r,x,y);
    tree[id]=max(tree[p1],tree[p2]);
}
int query(int id,int l,int r,int x,int y)
{
    if(x<=l&&r<=y) return tree[id];
    int mid=(l+r)/2;
    int s=0;
    if(y<=mid) return query(p1,l,mid,x,y);
    else
    if(x>mid) return query(p2,mid+1,r,x,y);
    else                                     
    return max(query(p1,l,mid,x,mid),query(p2,mid+1,r,mid+1,y));
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i].v);
        a[i].id=i;
        b[i]=a[i];
    }
    sort(a+1,a+n+1,cmp);
    lisanhua();
    for(int i=1;i<=n;i++)
    {
        if(i>1)
        {
            int x=b[i].v+m;
            int y=b[i].v-m;
            int xx=erfen1(1,n,x);
            int yy=erfen2(1,n,y);
            while(x>a[xx].v&&xx<=n) xx++;
            while(y<a[yy].v&&yy>=1) yy--;
            if(1<=xx&&xx<=n) xx=li[xx];
            if(yy>=1&&yy<=n) yy=li[yy];
            f[i]=0;
            if(xx<=n) f[i]=max(f[i],query(1,1,n,xx,n));
            if(yy>=1) f[i]=max(f[i],query(1,1,n,1,yy));
            f[i]++;
        }
        else f[i]=1;
        update(1,1,n,pre_do[i],f[i]);
        ans=max(ans,f[i]);
    }
    cout<<ans<<endl;
    return 0;
}


### Codeforces 887E Problem Solution and Discussion The problem **887E - The Great Game** on Codeforces involves a strategic game between two players who take turns to perform operations under specific rules. To tackle this challenge effectively, understanding both dynamic programming (DP) techniques and bitwise manipulation is crucial. #### Dynamic Programming Approach One effective method to approach this problem utilizes DP with memoization. By defining `dp[i][j]` as the optimal result when starting from state `(i,j)` where `i` represents current position and `j` indicates some status flag related to previous moves: ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = ...; // Define based on constraints int dp[MAXN][2]; // Function to calculate minimum steps using top-down DP int minSteps(int pos, bool prevMoveType) { if (pos >= N) return 0; if (dp[pos][prevMoveType] != -1) return dp[pos][prevMoveType]; int res = INT_MAX; // Try all possible next positions and update 'res' for (...) { /* Logic here */ } dp[pos][prevMoveType] = res; return res; } ``` This code snippet outlines how one might structure a solution involving recursive calls combined with caching results through an array named `dp`. #### Bitwise Operations Insight Another critical aspect lies within efficiently handling large integers via bitwise operators instead of arithmetic ones whenever applicable. This optimization can significantly reduce computation time especially given tight limits often found in competitive coding challenges like those hosted by platforms such as Codeforces[^1]. For detailed discussions about similar problems or more insights into solving strategies specifically tailored towards contest preparation, visiting forums dedicated to algorithmic contests would be beneficial. Websites associated directly with Codeforces offer rich resources including editorials written after each round which provide comprehensive explanations alongside alternative approaches taken by successful contestants during live events. --related questions-- 1. What are common pitfalls encountered while implementing dynamic programming solutions? 2. How does bit manipulation improve performance in algorithms dealing with integer values? 3. Can you recommend any online communities focused on discussing competitive programming tactics? 4. Are there particular patterns that frequently appear across different levels of difficulty within Codeforces contests?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值