NYOJ备用2344 盖伦的告白(线段树||双端队列)

2344: 盖伦的告白

时间限制: 1 Sec   内存限制: 128 MB
提交: 56   解决: 19
[ 提交][ 状态][ 讨论版]

题目描述

盖伦和赵信这对基友又在打赌,谁输了就去向卡特琳娜告白。。

这一季中盖伦一如既往的怂。赵信为了帮他一把,故意表现出很厉害的样子,结果成功激活了盖伦的智商。

赵信手中有n张牌,每张牌上面有一个数,这些牌是非递减的。现在盖伦从他手中抽取k张牌,如果盖伦抽取后剩下的牌中相邻两张的差值的最大值最小,就算他赢。

结果当然是盖伦赢了。那么问题来了!

输入

第一行两个正整数n和k。

第二行n个数代表n张牌。

3≤n≤105

1≤k≤n-2

-109≤Ai≤109

输出

输出只有一个数,上述中的最小值。

样例输入

5 1
1 2 4 7 8
8 2
1 2 3 5 8 13 17 18
5 1
1 2 4 6 9

样例输出

3
5
2

链接:传送门

由于题目中给出 这些数字是非递减的,那么从中间删,肯定会产生更大差值所以要考虑从两边删

所以思路就是从两边删除k个元素,取剩下n-k个元素的最值即可,有两种写法

1:线段树O(nlogn)

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=100005;
ll a[N],t[N<<2];
void build(ll l,ll r,ll rt)
{
    if(l==r)
    {
        t[rt]=a[l+1]-a[l];
        return;
    }
    ll m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    t[rt]=max(t[rt<<1],t[rt<<1|1]);
}
ll query(ll x,ll y,ll l,ll r,ll rt)
{
    if(l>=x&&r<=y)
    {
        return t[rt];
    }
    ll m=(l+r)>>1;
    if(y<=m)
        return query(x,y,l,m,rt<<1);
    else if(x>m)
        return query(x,y,m+1,r,rt<<1|1);
    else
        return max(query(x,m,l,m,rt<<1),query(m+1,y,m+1,r,rt<<1|1));
}
int main()
{
    ll n,k;
    while(~scanf("%lld%lld",&n,&k))
    {
             mem(t,0);
            for(ll i=1;i<=n;i++)
            scanf("%lld",&a[i]);
            ll len=n-k-1,ans=0x3f3f3f3f;
            build(1,n-1,1);
            for(ll i=1;i+len<=n;i++)
                ans=min(ans,query(i,len+i-1,1,n-1,1));
                printf("%lld\n",ans);
    }
}
2.双端队列 O(n)

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=100010;
int a[N],diff[N],q[N],idx[N];
int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",a+i);
            if(i>1)diff[i-1]=a[i]-a[i-1];
        }
        int head=0,rear=0;
        for(int i=1;i<=n-k-1;i++)
        {
            while(head<rear&&q[rear-1]<=diff[i])
                rear--;
            q[rear]=diff[i];
            idx[rear++]=i;
        }
        int ans=q[head];
        for(int i=n-k;i<=n-1;i++)
        {
            while(head<rear&&q[rear-1]<=diff[i])
                rear--;
            q[rear]=diff[i];
            idx[rear++]=i;
            while(head<rear&&idx[head]<=i-n+k+1)head++;
            ans=min(ans,q[head]);
        }
        printf("%d\n",ans);
    }
    return 0;
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值