线段树|dp——cf 487 B

3 篇文章 0 订阅

http://codeforces.com/contest/487/problem/B
唉,比赛的时候想出思路了没有AC,唉;
我还是太弱了;
n*n的暴力大家都会的吧;
就是枚举i,再枚举j(1~i-L+1)
那么我们设一个k
表示j从后往前枚举的时候第一个遇到max-min>s的下标;
显然1~k都是不可以的;
k+1~i-L+1都是可以的;
如果我们找到这个k;
是不是可以用RMQ直接求出最优解更新f[i]
那怎么找到这个k呢;
我们利用二分,二分咋么知道一个区间的最小最大值呢?
用线段树;

#include<bits/stdc++.h>
#define Ll long long
using namespace std;
const int N=1e5+5;
struct tree{int l,r,v,ma,mi;}T[N*8];
int f[N],a[N];
int n,m,s,L;
void up(int num){
    T[num].ma=max(T[num*2].ma,T[num*2+1].ma);
    T[num].mi=min(T[num*2].mi,T[num*2+1].mi);
    T[num].v=min(T[num*2].v,T[num*2+1].v);
}
void make(int num,int l,int r){
    T[num].l=l; T[num].r=r;
    T[num].ma=-1e9;T[num].v=1e9;
    T[num].mi=1e9;
    if(l==r){ 
        T[num].ma=T[num].mi=a[l];
        return;
    }
    int mid=l+r>>1;
    make(num*2  ,l,mid  );
    make(num*2+1,mid+1,r);
    up(num);
}
void add(int num,int x,int v){
    if(T[num].l==T[num].r){T[num].v=v;return;}
    if(T[num*2].r>=x)add(num*2,x,v);else add(num*2+1,x,v);
    up(num);
}
int out(int num,int x,int y){
    if(x<=T[num].l&&T[num].r<=y)return T[num].v;
    int ans=1e9;
    if(T[num*2  ].r>=x)ans=min(ans,out(num*2  ,x,y));
    if(T[num*2+1].l<=y)ans=min(ans,out(num*2+1,x,y));
    return ans;
}
int outma(int num,int x,int y){
    if(x<=T[num].l&&T[num].r<=y)return T[num].ma;
    int ans=-1e9;
    if(T[num*2  ].r>=x)ans=max(ans,outma(num*2  ,x,y));
    if(T[num*2+1].l<=y)ans=max(ans,outma(num*2+1,x,y));
    return ans;
}
int outmi(int num,int x,int y){
    if(x<=T[num].l&&T[num].r<=y)return T[num].mi;
    int ans=1e9;
    if(T[num*2  ].r>=x)ans=min(ans,outmi(num*2  ,x,y));
    if(T[num*2+1].l<=y)ans=min(ans,outmi(num*2+1,x,y));
    return ans;
}
int er(int k){
    int l=1,r=k-L+1,mid,ans=1e9;
    while(r>=l){
        mid=l+r>>1;
        if(outma(1,mid,k)-outmi(1,mid,k)<=s)r=mid-1,ans=min(ans,mid);else l=mid+1;
    }
    return ans;
}
int main()
{
    scanf("%d%d%d",&n,&s,&L);
    if(L>n){printf("-1");return 0;}
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    make(1,1,n);
    for(int i=L;i<=n;i++){
        int k=er(i);
        if(k==1e9)f[i]=1e9;else
        if(k==1)f[i]=1;else
        f[i]=out(1,k-1,i-L)+1;
        add(1,i,f[i]);
    }
    if(f[n]>=1e9)printf("-1");else printf("%d",f[n]);
}

这道题用单调队列也是可以做的;
因为k一直变大不会减小;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值