[Offer收割]编程练习赛51- C 等差子数列

题目3 : 等差子数列


很久没做题手生了许多。
题意:中文题。
思路:关键在于连续。一个数要么和前两个构成等差,长度加一;要么和前一个构成新的等差,长度为2,前提是前一个存在。那么我们可以写出每个数的位置所能达到的最长的等差连续子序列。
如:

    1 2 3 5 7 9

对应:1 2 3 2 3 4

这样貌似只需查询区间最值即可,但切勿忽略一个问题:如果上述数列查询的区间为[2,4],ans应为2而不是3。这种情况id=3的位置实际贡献应该是2.

假设区间某一位置id的连续最长等差子序列长度为ma:

① ma<=id-l+1 : ans=ma(此序列完全包含在所查询区间内)

② ma>id-l+1 : ans=id-l+1 ???这个ans只能代表前面一小段的贡献,而后面的可能有更长的。

比如: 1 2 3 4 1 2 3,查询区间[3,7],正确答案应该是3.

所以在②的情况下,还需要查询后面一小段的最大值即可,这一小段能保证全在查询区间内。然后ANS=max(id-l+1,post_max).

我们在查询的时候需要知道最大值及其位置。也就是很简单的线段树,但很久没写代码了调了半天。

//头文件已删
#define sc(x) scanf("%d",&x)
#define pd(x) printf("%d\n",x)
#define cls(a,x) memset(a,x,sizeof(a))
const double eps=1e-8;
const double PI=acos(-1.0);
const int INF=1e9+10;
const int mod=1e9+7;
const int N=2e5+10;
int c[N],b[N],n,m;
//char s[N];
struct node
{
    int l,r;
    int ma,id;
}a[N<<2];
void build(int l,int r,int k)
{
    a[k].l=l,a[k].r=r,a[k].ma=0,a[k].id=0;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(l,mid,2*k);
    build(mid+1,r,2*k+1);
}
void in(int pos,int num,int k)
{
    if(a[k].l==a[k].r&&a[k].l==pos)
    {
        a[k].ma=num;
        a[k].id=pos;
        return ;
    }
    int mid=(a[k].l+a[k].r)>>1;
    if(pos<=mid) in(pos,num,2*k);
    else in(pos,num,2*k+1);
    if(a[k*2+1].ma>=a[k*2].ma) a[k].ma=a[k*2+1].ma,a[k].id=a[k*2+1].id;
    else a[k].ma=a[k*2].ma,a[k].id=a[k*2].id;
}
int id,maxx;//得到最大值,与最大值的位置
void Q1(int l,int r,int k)
{
    if(l>r) return ;
    if(a[k].l==l&&a[k].r==r)
    {
//      printf("l=%d r=%d  maxx=%d id=%d\n",l,r,a[k].ma,a[k].id);
        if(a[k].ma>maxx)
        {
            maxx=a[k].ma;
            id=a[k].id;
        }
        else if(a[k].ma==maxx&&a[k].id>id) id=a[k].id;
        return ;
    }
    int mid=(a[k].l+a[k].r)>>1;
    if(r<=mid) Q1(l,r,2*k);
    else if(l>mid) Q1(l,r,2*k+1);
    else
    {
        Q1(l,mid,2*k);
        Q1(mid+1,r,2*k+1);
    }
}
int main()
{
    while(~sc(n))
    {
        sc(m);
        build(1,n,1);
        b[0]=0;
        int la=0;
        for(int i=1; i<=n; i++)
        {
            sc(c[i]);
            if(i<=2)
            {
                if(i==2) la=c[i]-c[i-1];
                b[i]=i;
            }
            else
            {
                if(c[i]-c[i-1]==la) b[i]=max(2,b[i-1]+1);
                else la=c[i]-c[i-1],b[i]=2;
            }
        }
        for(int i=1; i<=n; i++)in(i,b[i],1);// printf("%d%c",b[i],i==n?'\n':' '),
        int l,r;
        while(m--)
        {
            sc(l);
            sc(r);
            if(l>r) swap(l,r);
            if(r-l+1<=2) printf("%d\n",r-l+1);
            else
            {
                maxx=0,id=0;//先求出最大值及其位置
                Q1(l,r,1);
//                printf("ma=%d id=%d\n",maxx,id);
                if(maxx<=id-l+1) printf("%d\n",maxx);
                else
                {
                    int now_ma=id-l+1;//只能有这么多的贡献
                    maxx=0;
//                    printf("id+1=%d r=%d\n",id+1,r);
                    Q1(id+1,r,1);
                    printf("%d\n",max(now_ma,maxx));
                }
            }
        }
    }
}
//6 2
//1 2 3 5 7 9
//2 6
//1 4
//
//7 8
//1 2 3 4 1 2 3
//2 6


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《后端 offer 收割机养成指南》是一本有关后端技术与求职的指南,主要面向想要成为后端工程师的人群。这份PDF提供了一些实用的技术知识和求职建议,有助于读者了解后端技术的要点和掌握核心技能。 首先,这本指南详细介绍了后端工程师的职责和岗位要求。后端工程师主要负责构建和维护服务器端的数据处理逻辑和业务逻辑。他们需要具备扎实的编程基础,熟悉常用的后端开发语言和框架,如Java、Python、Node.js等,并能够熟练使用数据库。 指南中还介绍了一些后端工程师常用的技术栈和工具,如RESTful API、微服务架构、消息队列等。这些技术和工具是现代后端开发中不可或缺的组成部分,掌握它们将有助于提升后端工程师的工作效率和开发质量。 此外,这本指南还分享了一些求职的经验和建议。它提供了寻找后端工程师职位的途径和方法,并给出了一些面试准备和面试技巧。通过学习这些经验和建议,读者可以更好地应对后端工程师的面试挑战,并提升自己的求职竞争力。 总而言之,《后端 offer 收割机养成指南》是一本对于想要成为后端工程师的人们非常有价值的指南。它不仅提供了掌握后端技术的核心知识和技能,还分享了求职方面的经验和建议。希望这本指南对读者在后端领域的学习和求职之路上有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值