【Monotonic-queue】【dp】【Segment-tree】【STL】Codeforces 487B - Strip

来源:互联网 发布:ubuntu kylin 14.04 编辑:程序博客网 时间:2024/06/05 16:18

Codeforces 487B - Strip :http://codeforces.com/problemset/problem/487/B

Description:

Alexandra has a paper strip with n numbers on it. Let's call them ai from left to right.

Now Alexandra wants to split it into some pieces (possibly 1). For each piece of strip, it must satisfy:

  • a、Each piece should contain at least l numbers.
  • b、The difference between the maximal and the minimal number on the piece should be at most s.

Please help Alexandra to find the minimal number of pieces meeting the condition above.

Input

The first line contains three space-separated integers n, s, l (1 ≤ n ≤ 105, 0 ≤ s ≤ 109, 1 ≤ l ≤ 105).

The second line contains n integers ai separated by spaces ( - 109 ≤ ai ≤ 109).

Output

Output the minimal number of strip pieces.

If there are no ways to split the strip, output -1.


It's easy to understand what's the description talking about.

I had no idea when I first see the question.After a deep thought,an idea came to me and I began to write.I used a queue to record each condition.Almost each condition can expand into two conditions that led to Memory limit exceeded.The first submission was wrong.

Then I read the tutorial.The tutorial uses the method of dp using two arrays f[i] and g[i].

f[i] records how many pieces at least from the first item.But how to transform from smaller conditions?At first ,a piece should include at least l items.So k is at mosti-lif it's legal.Then,what's the left limit?It's decided by how long is legal as left as possible.It means that between k to i the biggest item minus the smallest item is less than or equal to s  but between k-1 to i is not.

So we also need to find the left most position in accordance with condition b.

g[i] denote the maximal length of substrip whose right border is i(included) and it satisfy the condition.So k is at least i-g[i].

f[i]=min{ f[k] }+1     (i-g[i]<=k<=i-l)

The tutorial told me to use monotonic queue to solve g[i].I'm learning about monotonic queue,so I did it as tutorial.

I used two monotonic queues.One records the biggest item and the other records the smallest one.

The second submission was also wrong because I only recorded the position of the biggest and the smallest without recording other messages  .So I modified my code adding two queues to record left most item .

The third submission was time limit exceeded.Because It would be O(n^2) if every g[i]=i.

For example,

100000 3 4

0 0 0 0 0 0 0 .....0

It's easy to get the answer which is one,but g[i] = {1,2,3,4,5,.....100000} so that each k is from 0 to i-4 for each i.

Actually,I don't know how to solve this problem.However,I just add a condition that when the biggest minus the smallest from i=1 to i=n,output 1 or -1 directly to avoid O(n^2)。It is accepted!Amazing!

I think it is because of lucky...

Now paste myugly accepted code.

#define _CRT_SECURE_NO_WARNINGS#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <stack>#include <set>#include <map>#include <fstream>using namespace std;//#define ll __int64#define ll long long#define L(u) ((u)<<1)#define R(u) ((u)<<1|1)#define lowbit(x) ((x)&-(x))#define PB push_back#define sq(x) ((x)*(x))#define rep(i,x,y) for(i=x;i<=y;i++)#define rep0(i,x,y) for(i=x;i<y;i++)#define mem(a, num) memset(a, num, sizeof(a))#define cpy(to, from) memcpy(to, from, sizeof(from))#define sd(x) scanf("%d",&x)#define sd2(x,y) scanf("%d%d",&x,&y)#define sd3(x,y,z) scanf("%d%d%d",&x,&y,&z)//#define slld(x) scanf("%I64d",&x)//#define slld2(x,y) scanf("%I64d%I64d",&x,&y)//#define slld3(x,y,z) scanf("%I64d%I64d%I64d",&x,&y,&z)#define slf(x) scanf("%lf",&x)#define slf2(x,y) scanf("%lf%lf",&x,&y)#define sc(c) scanf("%c",&c);#define ss(st) scanf("%s",st);#define pd(x) printf("%d\n",x);#define plld(x) printf("%I64d\n",x);#define pcas() printf("Case %d: ", ++cas)#define pn() putchar(10);#define SA(a,i,n) rep(i,1,n) sd(a[i])#define SA0(a, i, n) rep0(i,0,n) sd(a[i])#define PA(a,i,n) rep0(i,1,n) printf("%d ", a[i]); pd(a[(n)])#define PA0(a, i, n) rep0(i,0,(n)-1) printf("%d ", a[i]); pd(a[(n) - 1])#pragma comment(linker, "/STACK:102400000,102400000")const int N = 300;const int M = 100005;const int INF = 0x3f3f3f3f;const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;const double pi = acos(-1.0);int q1[M],q2[M],a[M],f[M],g[M];int p1[M],p2[M];int main(){    int n,s,l;    while(scanf("%d%d%d",&n,&s,&l)!=EOF){        int maxx=-INF;        int minn=INF;        for(int i=1;i<=n;i++){            scanf("%d",&a[i]);            maxx=max(maxx,a[i]);            minn=min(minn,a[i]);        }        if(maxx-minn<=s){            printf("%d\n",l<=n?1:-1);            continue;        }        int be1=1,be2=1,end1=1,end2=1;        for(int i=1;i<=n;i++){            int t1=i,t2=i;            while(end1!=be1&&a[i]>=a[q1[end1-1]]){                t1=p1[--end1];            }            q1[end1]=i;            p1[end1++]=t1;            while(end2!=be2&&a[i]<=a[q2[end2-1]]){                //end2--;                t2=p2[--end2];            }            p2[end2]=t2;            q2[end2++]=i;            while(be1<end1&&be2<end2&&a[q1[be1]]-a[q2[be2]]>s){                if(q1[be1]<q2[be2]){                    be1++;                }                else if(q1[be1]>q2[be2]){                    be2++;                }                else{                    be1++;                    be2++;                }            }            g[i]=i-max(p1[be1],p2[be2])+1;        }        f[1]=1;        for(int i=2;i<=n;i++){               int minn=INF;            for(int j=i-g[i];j<=i-l;j++){                if(f[j]<minn){                    minn=f[j];                }            }            if(minn==INF) f[i]=INF;            else f[i]=minn+1;        }        if(f[n]==INF) cout<<-1<<endl;        else cout<<f[n]<<endl;    }    return 0;}


I searched others in the Internet .Most people use segment-tree and dp. 

segment-tree+dp: http://www.tuicool.com/articles/Ar2eaa

There is a magic way using STL which is short.

STL: http://www.cnblogs.com/zyue/p/4360175.html

// File Name: 487b.1.cpp// Author: darkdream// Created Time: 2015年03月23日 星期一 15时24分56秒#include<vector>#include<list>#include<map>#include<set>#include<deque>#include<stack>#include<bitset>#include<algorithm>#include<functional>#include<numeric>#include<utility>#include<sstream>#include<iostream>#include<iomanip>#include<cstdio>#include<cmath>#include<cstdlib>#include<cstring>#include<ctime>#define LL long long#define N 100007using namespace std;multiset<int> st,rt;int dp[N],n,l,s,a[N];int main(){  scanf("%d %d %d",&n,&s,&l);  for(int i = 1;i <= n;i ++)      scanf("%d",a+i);  for(int i = 1,j = 1;i <= n;i ++)  {      st.insert(a[i]);      for(;*st.rbegin() - *st.begin() > s;j ++)      {          st.erase(st.find(a[j]));          if(i - j >= l) rt.erase(rt.find(dp[j-1]));      }      if(i - j + 1 >= l) rt.insert(dp[i-l]);      if(rt.begin() == rt.end())  dp[i] = N;      else dp[i] = *rt.begin() + 1;   }  printf("%d\n",dp[n] >= N?-1:dp[n]);return 0;}


0 0