当前位置: 代码迷 >> 综合 >> Codeforces - Strip
  详细解决方案

Codeforces - Strip

热度:19   发布时间:2024-01-31 01:44:27.0

题目链接:Codeforces - Strip


显然可以dp。

然后枚举右端点的时候,左端点具有二分性,然后在对于的区间当中从最小的值转移即可。

最小值可以用线段树维护。

不过似乎这个是单调的,可以直接从最左端的点转移。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int n,cl,s,f[N][20],g[N][20],mi[N<<2],dp[N],a[N];
int ask(int l,int r,int fg){int k=log2(r-l+1);return fg?max(f[l][k],f[r-(1<<k)+1][k]):min(g[l][k],g[r-(1<<k)+1][k]);
}
int check(int l,int r){return ask(l,r,1)-ask(l,r,0)<=s;}
#define mid (l+r>>1)
void change(int p,int l,int r,int x,int v){if(l==r){mi[p]=min(mi[p],v);	return ;}if(x<=mid)	change(p<<1,l,mid,x,v);else	change(p<<1|1,mid+1,r,x,v);mi[p]=min(mi[p<<1],mi[p<<1|1]);
}
int ask(int p,int l,int r,int ql,int qr){if(l==ql&&r==qr)	return mi[p];if(qr<=mid)	return ask(p<<1,l,mid,ql,qr);else if(ql>mid) return ask(p<<1|1,mid+1,r,ql,qr);else return min(ask(p<<1,l,mid,ql,mid),ask(p<<1|1,mid+1,r,mid+1,qr));
}
#undef mid
signed main(){cin>>n>>s>>cl;	memset(mi,0x3f,sizeof mi),memset(dp,0x3f,sizeof dp);memset(g,0x3f,sizeof g);for(int i=1;i<=n;i++)	scanf("%d",&a[i]),f[i][0]=g[i][0]=a[i];for(int j=1;j<=18;j++)	for(int i=1;i<=n-(1<<j)+1;i++)f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]),g[i][j]=min(g[i][j-1],g[i+(1<<(j-1))][j-1]);dp[0]=0;	change(1,0,n,0,0);for(int i=cl;i<=n;i++){if(!check(i-cl+1,i))	continue;int L=1,R=i-cl+1;while(L<R){int mid=L+R>>1;if(check(mid,i))	R=mid;else	L=mid+1;}dp[i]=ask(1,0,n,L-1,i-cl)+1;change(1,0,n,i,dp[i]);}if(dp[n]>=0x3f3f3f3f)	puts("-1");else	cout<<dp[n];return 0;
}