codeforce 689D 【二分+RMQ】

来源:互联网 发布:cos图片特效软件 编辑:程序博客网 时间:2024/06/04 19:26

题意:

给出长度都为n(1<=n<=2e5)的两数组a[i]与b[i],求有多少组l与r使

比如a = {1,2,3,2,1,4},b={6,7,1,2,3,2} 有两组l与r符合条件:1.l=4,r=4,max=min=2;2.l=4,r=5,max=min=2。


题解:

我们可以思考当l固定时,可以通过求解r的范围[left,righ]得到(right-left)组符合条件的l与r,这个r的范围求解可以通过二分来求解, 判断在某个范围[l,r]是否符合条件可以通过RMQ在O(1)时间内处理,具体思路如下:

当r在范围[left,right]中可能存在符合条件的值时判断mid(mid=(left+right)/2)是否符合条件,若在[l,mid]范围,Max>Min则说明符合条件的r在[eftl,mid-1]中,Max<Min则说明符合条件的r在[mid+1,right]中,当Max==Min时符合条件的r最小值在[left,mid-1]符合条件的r的最大值在[mid+1,right]中。

这样就可以在O(2*log(n))求解某个固定值l下符合条件的r的范围,再枚举l就可以得到答案,总的时间复杂度为O(n*2*log(n))


#include<iostream>#include <stdio.h>#include <algorithm>#include <cmath>#include<stdlib.h>#include <string.h>#include<queue>#include<set>#include<map>#include<stack>#include<time.h>using namespace std;#define MAX_N 200005#define inf 0x7fffffff#define LL long long#define ull unsigned long long#define mod 1000000007LL INF=9e18;int a[MAX_N];int b[MAX_N];int minsum[MAX_N][20];int maxsum[MAX_N][20];void init_RMQ(int n){    for(int i=1;i<=n;i++)        maxsum[i][0] = a[i], minsum[i][0] = b[i];    int k = log2(1.0*n);    for(int j=1;j<=k;j++) {        for(int i=1;i<=n;i++) {            if(i+(1<<j)-1<=n) {                maxsum[i][j] = max(maxsum[i][j-1], maxsum[i+(1<<(j-1))][j-1]);                minsum[i][j] = min(minsum[i][j-1], minsum[i+(1<<(j-1))][j-1]);            }        }    }}int getMax(int i,int j){    int k = (int)log2(1.0*(j-i+1));    return max(maxsum[i][k], maxsum[j-(1<<k)+1][k]);}int getMin(int i,int j){    int k = (int)log2(1.0*(j-i+1));    return min(minsum[i][k], minsum[j-(1<<k)+1][k]);}int main(){    int n;    cin >> n;    for(int i=1;i<=n;i++)        scanf("%d",&a[i]);    for(int i=1;i<=n;i++)        scanf("%d",&b[i]);    init_RMQ(n);    LL ans = 0;    //固定left,二分right    for(int i=1;i<=n;i++) {        //如果a[i]比b[i]则跳过,因为接下来Max只会更大Min只会更小        if(a[i] > b[i])            continue;        int low = i;        int up = n;        int l = 0;        int r = 0;        while(low <= up) {            int mid = (low + up) / 2;            int Max = getMax(i, mid);            int Min = getMin(i, mid);            if(Max > Min)                up = mid - 1;            else if(Max < Min)                low = mid + 1;            else//假如mid符合条件则right最小值向low靠拢                l = mid, up = mid - 1;        }        if(l) {//假如存在符合条件的最小值则搜索最大值            up = n;            low = l;            while(low <= up) {                int mid = (low + up) / 2;                int Max = getMax(i, mid);                int Min = getMin(i, mid);                if(Max > Min)                    up = mid - 1;                else if(Max < Min)                    low = mid + 1;                else//假如mid符合条件则right最大值向up靠拢                    r = mid, low = mid + 1;            }        }        //printf("%d %d %d\n",i,l,r);        if(l && r) {            ans = ans + (LL)(r - l) + 1;        }    }    cout << ans << endl;}


0 0
原创粉丝点击