CSU1553 Good subsequence —— 二分 + RMQ/线段树

来源:互联网 发布:鸿图网络危机公关公司 编辑:程序博客网 时间:2024/06/06 03:34

题目链接: http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1553


Description

Give you a sequence of n numbers, and a number k you should find the max length of Good subsequence. Good subsequence is a continuous subsequence of the given sequence and its maximum value - minimum value<=k. For example n=5, k=2, the sequence ={5, 4, 2, 3, 1}. The answer is 3, the good subsequence are {4, 2, 3} or {2, 3, 1}.

Input

There are several test cases.
Each test case contains two line. the first line are two numbers indicates n and k (1<=n<=10,000, 1<=k<=1,000,000,000). The second line give the sequence of n numbers a[i] (1<=i<=n, 1<=a[i]<=1,000,000,000). 
The input will finish with the end of file.

Output

For each the case, output one integer indicates the answer.

Sample Input

5 25 4 2 3 11 11

Sample Output

31


题解:

之前学了RMQ,线段树, 树状数组,但是一直不知道他们在哪里能派上用场。通过这题,终于找到他们的用武之地了:区间查询最大最小值。

解决了查询区间最大最小值的问题,剩下的就是二分了。这里是二分长度。



RMQ:

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <string>#include <vector>#include <map>#include <set>#include <queue>#include <sstream>#include <algorithm>using namespace std;#define pb push_back#define mp make_pair#define ms(a, b)  memset((a), (b), sizeof(a))//#define LOCAL#define eps 0.0000001#define LNF (1<<60)typedef long long LL;const int inf = 0x3f3f3f3f;const int maxn = 10000+10;const int mod = 1e9+7;LL st_max[maxn][16], st_min[maxn][16];LL a[maxn];void RMQ_init(int n){    for(int i = 0; i<n; i++)    {        st_min[i][0] = a[i];        st_max[i][0] = a[i];    }    for(int j = 1; (1<<j)<=n; j++)//枚举长度    for(int i = 0; i+(1<<j)-1<n; i++)//枚举起点    {        st_min[i][j] = min(st_min[i][j-1],st_min[i+(1<<(j-1))][j-1]);        st_max[i][j] = max(st_max[i][j-1],st_max[i+(1<<(j-1))][j-1]);    }}LL RMQ(int l, int r)//查询{    int k = 0;    while((1<<(k+1))<=r-l+1)        k++;    return max(st_max[l][k],st_max[r-(1<<k)+1][k]) - min(st_min[l][k],st_min[r-(1<<k)+1][k]);}int test(int len, int n, int k){    for(int i = len-1; i<n; i++)        if(RMQ(i-len+1, i)<=1LL*k)            return 1;    return 0;}int main(){#ifdef LOCAL    freopen("input.txt", "r", stdin);//      freopen("output.txt", "w", stdout);#endif // LOCAL    int n, k;    while(~scanf("%d%d", &n, &k))    {        for(int i=0;i<n;i++)            scanf("%lld", &a[i]);        ms(st_max, 0);        ms(st_min, 0);        RMQ_init(n);        int l = 1, r = n;        while(l<=r)        {            int mid = (l+r)/2;            if(test(mid, n, k))                l = mid+1;            else                r = mid-1;        }        printf("%d\n", r);    }    return 0;}


线段树:

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <string>#include <vector>#include <map>#include <set>#include <queue>#include <sstream>#include <algorithm>using namespace std;#define pb push_back#define mp make_pair#define ms(a, b)  memset((a), (b), sizeof(a))//#define LOCAL#define eps 0.0000001#define LNF 1000000000000typedef long long LL;const int inf = 0x3f3f3f3f;const int maxn = 10000+10;const int mod = 1e9+7;LL st_max[4*maxn], st_min[4*maxn];LL a[maxn];void build(int rt, int l, int r){    if(l==r)    {        st_max[rt] = a[r];        st_min[rt] = a[r];        return;    }    int mid = (l+r)>>1;    build(rt*2,l,mid);    build(rt*2+1,mid+1,r);    st_max[rt] = max(st_max[rt*2], st_max[rt*2+1]);    st_min[rt] = min(st_min[rt*2], st_min[rt*2+1]);}//由于最大最小值都要查询,而return只能返回一个,所以用ma和mi记录最小值LL query(int rt, int l, int r, int x, int y, LL &ma, LL &mi){    if(x<=l && y>=r)    {        ma = max(ma,st_max[rt]);        mi = min(mi,st_min[rt]);        return ma - mi;    }    int mid = (l+r)>>1;    if(y<=mid) query(rt*2,l,mid,x,y,ma,mi);    else if(x>=mid+1) query(rt*2+1,mid+1,r,x,y,ma,mi);    else query(rt*2,l,mid,x,mid,ma,mi),query(rt*2+1,mid+1,r,mid+1,y,ma,mi);    return ma - mi;}int test(int len, int n, int k){    for(int i = len-1; i<n; i++)    {        LL ma = -LNF, mi = LNF;        if(query(1,0,n-1, i-len+1, i, ma,mi)<=1LL*k)            return 1;    }    return 0;}int main(){#ifdef LOCAL    freopen("input.txt", "r", stdin);//      freopen("output.txt", "w", stdout);#endif // LOCAL    int n, k;    while(scanf("%d%d", &n, &k)!=EOF)    {        for(int i=0;i<n;i++)            scanf("%lld", &a[i]);        build(1,0,n-1);        int l = 1, r = n;        while(l<=r)        {            int mid = (l+r)/2;            if(test(mid, n,k))                l = mid+1;            else                r = mid-1;        }        printf("%d\n", r);    }    return 0;}


0 0
原创粉丝点击