codeforces基础题——#361(div2)D

来源:互联网 发布:ajax解析嵌套json数据 编辑:程序博客网 时间:2024/05/22 11:43

#361(Div 2) D

题目大意 :给你a, b两个长度为n的整数序列(1 <= n <= 200000), 问有多少个(l, r)(1  <= l, r  <=  n )使得a中区间(l, r)的最大值与b中区间(l, r)的最小值一样题解 : 一开始在想神奇的树状数组瞎搞做法, 其实可以做, 但写起来很麻烦, 于是写到一半太累(懒)了, 就没再写……此题正解十分简洁, 枚举左端点l,然后找右端点r的可行位置, 我们发现如果从i 到 i + j可行, 而i + j + 1不可行, 那么在之后应定不会有可行的右端点, 因为a中区间最大值只会增加, 而b中区间的最小值只会减少, 所以右端点r的可行位置一定在一段连续的区间中。那么怎找到这段区间呢, 注意左端点确定时,最大值与最小值具有单调性, 所以如果我们利用RMQ欲处理出最大值和最小值, 就能二分把区间找到,具体如下:    如果a中(l, mid)大于b中(l, mid)的值, 那么(mid + 1, r)的值一定是不合法的, 所以查找区间(l, mid), 合法的值一定在(mid + 1, r)中, 查找(mid +1, r);    通过比较大于和大于等于找出区间的左端点和右端点, 更新答案(然而我这里之前没想通,  wa了几百次)    所以RMQ预处理, 暴力枚举l, 二分r可行区间即可, 时间复杂度O(nlogn)
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int a[200100], b[200100], n;int st1[200100][21], st2[200100][21], p[21], lg[200100];int rmq1(int i, int j){    int k = lg[j - i + 1];    return max(st1[i][k], st1[j - p[k] + 1][k]);}int rmq2(int i, int j){    int k = lg[j - i + 1];    return min(st2[i][k], st2[j - p[k] + 1][k]);}int main(){    scanf("%d", &n);    for (int i = 1; i <= n; i ++)scanf("%d", &a[i]);    for (int i = 1; i <= n; i ++)scanf("%d", &b[i]);    int tmp = 2;p[0] = 1;    for (int i = 1; i <= 20; i ++) p[i] = p[i - 1] * 2;    for (int i = 2; i <= n; i ++) {        lg[i] = lg[i - 1];        if (tmp <= i) lg[i] ++, tmp *= 2;        //printf("%d %d\n", i, lg[i]);    }    for (int i = 1; i <= n; i ++) st1[i][0] = a[i], st2[i][0] = b[i];    for (int i = 1; i <= 20 && p[i] <= n; i ++)        for (int j = 1; j <= n && j + p[i] - 1 <= n; j ++){            st1[j][i] = max(st1[j][i - 1], st1[j + p[i - 1]][i - 1]);            st2[j][i] = min(st2[j][i - 1], st2[j + p[i - 1]][i - 1]);        }    long long ans = 0;    for (int i = 1; i <= n; i ++){        if (a[i] > b[i]) continue;        int l = i, r = n;        while(l != r){            int mid = (l + r) >> 1;            if (rmq1(i, mid) >= rmq2(i, mid)) r = mid;            else l = mid + 1;        }        if (rmq1(i, r) != rmq2(i, l)) continue;        int p = l;        l = i, r = n + 1;        while(l != r){            int mid = (l + r) >> 1;            if (rmq1(i, mid) > rmq2(i, mid)) r = mid;            else l = mid + 1;//printf("%d %d\n", l, r);        }        ans += l - p;//      }    printf("%I64d\n", ans);    return 0;}
0 0
原创粉丝点击