RMQ+二分 - CF 689D Friends and Subsequences

来源:互联网 发布:代运营淘宝 编辑:程序博客网 时间:2024/05/16 08:52

题目:

Friends and Subsequences

题意:

给A,B两个序列,求maxri=l(Ai)=minri=l(Bi)的区间数量

思路:

在所有的区间中求极大/小值,第一反应就应该是二分。
当l为定值,随着x的增大,maxxl=iArri是一个单调不减函数,同理,minxl=iArri是一个单调不增函数,这里不给出证明,有兴趣自己想一下为什么。
有了上面的规律,很容易想到算法:用RMQ做预处理,然后枚举区间左值,二分区间右值,找到两个函数的相交部分即可,因为不是严格递增递减函数,所以相交部分有可能是一段而不仅仅是一个点,所以做两次二分,一次找到相交部分的左端点,一次找到右端点

代码:

#include <bits/stdc++.h>using namespace std;const int maxn = 2e5+10;int dmin[maxn][32], dmax[maxn][32];void RMQ_init(int A[], int B[], int len){    for (int i = 0; i<len; ++i){        dmin[i][0] = A[i];        dmax[i][0] = B[i];    }    for (int j = 1; (1 << j) <= len; ++j)    for (int i = 0; i + (1 << j) - 1<len; ++i){        dmin[i][j] = min(dmin[i][j - 1], dmin[i + (1 << (j - 1))][j - 1]);        dmax[i][j] = max(dmax[i][j - 1], dmax[i + (1 << (j - 1))][j - 1]);    }    return;}int RMQ_min(int L, int R){    int k = 0;    while (1 << (k + 1) <= R - L + 1) k++;    return min(dmin[L][k], dmin[R - (1 << k) + 1][k]);}int RMQ_max(int L, int R){    int k = 0;    while (1 << (k + 1) <= R - L + 1) k++;    return max(dmax[L][k], dmax[R - (1 << k) + 1][k]);}int arr1[maxn], arr2[maxn];int main(){    int n;    scanf("%d",&n);    for (int i=0;i<n;++i)        scanf("%d",arr1+i);    for (int i=0;i<n;++i)        scanf("%d",arr2+i);    RMQ_init(arr2, arr1, n);    long long sum = 0;    for (int i=0;i<n;++i){        int l = i, r = n-1, res1 = -1, res2 = -1;        if (RMQ_min(l,r)>RMQ_max(l,r)) continue;        while (l<=r){            int mid = (l+r) >> 1;            int minimum = RMQ_min(i,mid), maximum = RMQ_max(i,mid);            if (minimum == maximum)                res1 = res1 == -1 ? mid : max(res1, mid);            if (minimum < maximum)                r = mid - 1;            else                l = mid + 1;        }        if (res1 == -1) continue;        l = i, r = res1, res2 = -1;        while (l<=r){            int mid = (l+r) >> 1;            int minimum = RMQ_min(i,mid), maximum = RMQ_max(i,mid);            if (minimum == maximum)                res2 = res2 == -1 ? mid : min(res2, mid);            if (minimum <= maximum)                r = mid - 1;            else                l = mid + 1;        }        sum += res1 - res2 + 1;    }    cout<<sum<<endl;    return 0;}
0 0
原创粉丝点击