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一直变大不会减小;