Codeforces Round #278 (Div. 1) B

来源:互联网 发布:杜兰特软蛋知乎 编辑:程序博客网 时间:2024/06/12 09:10

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;  }  


0 0