B. Strip
题意:n个数,需要把他们切割成尽量少的部分,每部分连续,长度至少为l,其中最大数与最小数的差不能超过s。
思路:首先,预处理每个区间内的最大数和最小数(spare table),然后就可以用dp的方法解决这个问题。dp的时候,利用预处理,对每个位置i找到以i为结尾,最左边能在哪个地方切割(二分查找,位置记为j),所以以i结尾合法的切割范围就是j~i-l。如果在位置k切割,状态转移就是dp(i)=dp(k)+1。我们要做的就是从j~i-l转移到i,这个过程需要用线段树优化,不然会T。。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <math.h>
using namespace std;
const int maxn=100010;
const int INF=1e9+10;
int a[maxn];
int MIN[maxn][20];
int MAX[maxn][20];
int dp[maxn];
int getmin(int l,int r){
int d=r-l+1;
int k=-1;
while(d){
k++;
d>>=1;
}
return min(MIN[l][k],MIN[r-(1<<k)+1][k]);
}
int getmax(int l,int r){
int d=r-l+1;
int k=-1;
while(d){
k++;
d>>=1;
}
return max(MAX[l][k],MAX[r-(1<<k)+1][k]);
}
struct node{
int l,r;
int val;
}tree[maxn<<2];
void build_tree(int n,int l,int r){
tree[n].l=l; tree[n].r=r;
tree[n].val=INF;
if(l==r)return;
int mid=(l+r)>>1;
build_tree(n<<1,l,mid);
build_tree((n<<1)|1,mid+1,r);
}
inline void push_up(int n){
tree[n].val=min(tree[n<<1].val,tree[(n<<1)|1].val);
}
void update(int n,int pos,int v){
if(tree[n].l==tree[n].r){
tree[n].val=v;
return;
}
int mid=(tree[n].l+tree[n].r)>>1;
if(pos<=mid) update(n<<1,pos,v);
else update((n<<1)|1,pos,v);
push_up(n);
}
int query(int n,int l,int r){
if(tree[n].l==l&&tree[n].r==r){
return tree[n].val;
}
int mid=(tree[n].l+tree[n].r)>>1;
if(r<=mid){
return query(n<<1,l,r);
}else{
if(l>mid){
return query((n<<1)|1,l,r);
}else{
return min( query(n<<1,l,mid) , query((n<<1)|1,mid+1,r) );
}
}
}
int main(){
int n,s,L;
cin>>n>>s>>L;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
MAX[i][0]=MIN[i][0]=a[i];
}
int tmp=1;
int k=0;
while(tmp<n){
tmp<<=1;
k++;
}
for(int j=1;j<=k;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
MIN[i][j]=min(MIN[i][j-1],MIN[i+(1<<(j-1)) ][j-1]);
MAX[i][j]=max(MAX[i][j-1],MAX[i+(1<<(j-1)) ][j-1]);
}
}
for(int i=1;i<=n;i++)dp[i]=INF;
build_tree(1,0,n);
update(1,0,0);
for(int i=1;i<=n;i++){
int l=0,r=i-L;
int pos=-1;
while(l<=r){
int mid=(l+r)>>1;
if(getmax(mid+1,i)-getmin(mid+1,i)<=s){
pos=mid;
r=mid-1;
}else{
l=mid+1;
}
}
if(pos!=-1&&pos<=i-L){
int t=query(1,pos,i-L);
if(t>=INF)continue;
dp[i]=t+1;
update(1,i,dp[i]);
}
}
if(dp[n]>=INF) cout<<-1<<endl;
else cout<<dp[n]<<endl;
return 0;
}