zoukankan      html  css  js  c++  java
  • codeforces 361 D

    原题:

    Description

    Mike and !Mike are old childhood rivals, they are opposite in everything they do, except programming. Today they have a problem they cannot solve on their own, but together (with you) — who knows?

    Every one of them has an integer sequences a and b of length n. Being given a query of the form of pair of integers (l, r), Mike can instantly tell the value of  while !Mike can instantly tell the value of .

    Now suppose a robot (you!) asks them all possible different queries of pairs of integers (l, r)(1 ≤ l ≤ r ≤ n) (so he will make exactly n(n + 1) / 2 queries) and counts how many times their answers coincide, thus for how many pairs  is satisfied.

    How many occasions will the robot count?

    Input

    The first line contains only integer n (1 ≤ n ≤ 200 000).

    The second line contains n integer numbers a1, a2, ..., an ( - 109 ≤ ai ≤ 109) — the sequence a.

    The third line contains n integer numbers b1, b2, ..., bn ( - 109 ≤ bi ≤ 109) — the sequence b.

    Output

    Print the only integer number — the number of occasions the robot will count, thus for how many pairs  is satisfied.

    Sample Input

    Input
    6
    1 2 3 2 1 4
    6 7 1 2 3 2
    Output
    2
    Input
    3
    3 3 3
    1 1 1
    Output
    0

    Hint

    The occasions in the first sample case are:

    1.l = 4,r = 4 since max{2} = min{2}.

    2.l = 4,r = 5 since max{2, 1} = min{2, 3}.

    There are no occasions in the second sample case since Mike will answer 3 to any query pair, but !Mike will always answer 1.

     

     

    提示: 暴力比对所有区间时间复杂度是(n^2)无法通过。

    观察发现,如果固定区间左边界L,右边界R一次递增,a_max【L,R】是不减的,即有序。 同样b_min【L,R】是不增的,有序。

    所以就可以先枚举左端点,再用二分法去寻找右端点的合法(符合题意的)区间,这个区间会是一个连续的范围。

    二分的时候注意 RMQ_a(L,mid) = RMQ_b(L,mid) 的时候如何处理决定了最终结果是右端点的左边界还是右边界。

     

    求区间最值是使用了RMQ算法。(一个很精妙的算法,我之前的博客里有写。)

     

     

    代码:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    
    using namespace std;
    
    #define  MAX(x,y) (((x)>(y)) ? (x) : (y))
    #define  MIN(x,y) (((x) < (y)) ? (x) : (y))
    #define ABS(x) ((x)>0?(x):-(x))
    #define ll long long
    
    const int inf = 0x7fffffff;
    const int maxn=2e5+10;
    
    int a[maxn],b[maxn];
    int d_a[maxn][23];
    int d_b[maxn][23];
    
    void RMQ_init_a(int *A,int n)
    {
        for(int i=0; i<n; i++)  d_a[i][0]=A[i];
        for(int j=1; (1<<j)-1 < n; j++)
            for(int i=0; i+(1<<j)-1 < n; i++)
                d_a[i][j]=MAX( d_a[i][j-1], d_a[i + (1<<(j-1))][j-1] );
    }
    
    int RMQ_a(int L, int R)
    {
        int k=0;
        while( 1<<(k+1) <= R-L+1 )  k++;
        return MAX( d_a[L][k], d_a[R-(1<<k) + 1][k] );
    }
    
    void RMQ_init_b(int *A,int n)
    {
        for(int i=0; i<n; i++)  d_b[i][0]=A[i];
        for(int j=1; (1<<j)-1 < n; j++)
            for(int i=0; i+(1<<j)-1 < n; i++)
                d_b[i][j]=MIN( d_b[i][j-1], d_b[i + (1<<(j-1))][j-1] );
    }
    
    int RMQ_b(int L, int R)
    {
        int k=0;
        while( 1<<(k+1) <= R-L+1 )  k++;
        return MIN( d_b[L][k], d_b[R-(1<<k) + 1][k] );
    }
    
    int main()
    {
        int n;
        cin>>n;
        for(int i=0; i<n; i++)  scanf("%d",a+i);
        for(int i=0; i<n; i++)  scanf("%d",b+i);
        RMQ_init_a(a,n);
        RMQ_init_b(b,n);
        int left, right;
        ll ans = 0;
        for(int L=0; L<n; L++)
        {
            int left = inf, right = -inf;
            //求左边界
            int l = L;
            int r = n-1;
            while(l <= r)
            {
                int mid=(l + r)/2;
                if(RMQ_a(L,mid) > RMQ_b(L,mid)) //左半部分
                    r=mid-1;
                else if(RMQ_a(L,mid) < RMQ_b(L,mid))                             //右半部分
                        l=mid+1;
                    else
                    {
                        left = min(left, mid);
                        r=mid-1;
                    }
            }
    //        printf("left = %d
    ",left);
            //求右边界
            l = L;
            r = n-1;
             while(l <= r)
            {
                int mid=(l + r)/2;
                if(RMQ_a(L,mid) > RMQ_b(L,mid)) //左半部分
                {
                    r=mid-1;
                }
                else if(RMQ_a(L,mid) < RMQ_b(L,mid))                          //右半部分
                        l=mid+1;
                    else
                    {
                        right = max(right, mid);
                        l=mid+1;
                    }
            }
    //        printf("right = %d
    ",right);
            if(left != inf)
                ans += right - left + 1;
        }
        cout<<ans<<endl;
    
        return 0;
    }

     

  • 相关阅读:
    NKOJ P3051浇花
    Linux-Shell脚本编程-学习-2-Linux基本命令
    Linux-Shell脚本编程-学习-1-Linux基本命令
    Ubuntu下使用Git_6
    Ubuntu下使用Git_5
    电脑优化,提速
    Ubuntu下使用Git_4
    Ubuntu下使用Git_3
    Ubuntu下使用Git_2
    Ubuntu下使用Git_1
  • 原文地址:https://www.cnblogs.com/shawn-ji/p/5666099.html
Copyright © 2011-2022 走看看