链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=121473#problem/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 exactlyn(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
6
1 2 3 2 1 4
6 7 1 2 3 2
2
3
3 3 3
1 1 1
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.
题意:
有两个等长的序列a、b,求出在相同[l,r]区间的情况下,有序列a的最大值等于序列b的最小值这种结果的区间的总数。
解析:
这个要用到RMQ这个知识点,RMQ的预处理和查询有相应的模板,自己可以百度去了解记忆一下。
利用区间特性进行二分,固定区间左端点(注意区间左端点和二分左端点不一样)
确定最边缘左端点。
若二分形成的最小值小于最大值,这个区间可以通过减小右端点而最大值可以再变小,最小值可以再变大,说明仍可以左移区间右端点
若最小值大于最大值,则说明a区间中的数都小于b区间的最小值,只能右移区间左端点。
确定最边缘右端点和上诉一样。
若相等,则根据当前是求右边界最左端还是最右端进行相应移动。
求出每一区间左端点对应的区间右端点的两个位置极值,作差,求和,求得结果。
注意:5-1<<1的结果是4<<1,即等于8。
5-(1<<1)的结果是5-2,即等于3.
源代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 using namespace std; 5 int fa[200010][20]; 6 int fb[200010][20]; 7 int RMQ(int L,int R,int x) 8 { 9 int k=log((R-L+1)*1.0)/log(2.0); 10 if(x==0) 11 return max(fa[L][k],fa[R+1-(1<<k)][k]); 12 else 13 return min(fb[L][k],fb[R+1-(1<<k)][k]); 14 } 15 int main() 16 { 17 int n; 18 scanf("%d",&n); 19 int a,b; 20 for(int i=0;i<n;i++) 21 scanf("%d",&fa[i][0]); 22 for(int i=0;i<n;i++) 23 scanf("%d",&fb[i][0]); 24 for(int j=1;(1<<j)<=n;j++) 25 for(int i=0;i+(1<<j)<=n;i++) 26 { 27 fa[i][j]=max(fa[i][j-1],fa[i+(1<<(j-1))][j-1]); 28 fb[i][j]=min(fb[i][j-1],fb[i+(1<<(j-1))][j-1]); 29 } 30 int l,r,ma,mb,st,en,mid; 31 long long sum=0; 32 for(int i=0;i<n;i++) //固定查询的左端点 33 { 34 l=i; 35 st=-1; 36 r=n-1; 37 while(l<=r) //二分求取最边缘左端点 38 { 39 mid=(l+r)/2; 40 ma=RMQ(i,mid,0); 41 mb=RMQ(i,mid,1); 42 if(ma>=mb) 43 { 44 if(ma==mb) st=mid; 45 r=mid-1; 46 } 47 else 48 l=mid+1; 49 } 50 if(st==-1) continue; 51 l=i; 52 r=n-1; 53 en=-1; 54 while(l<=r) //二分求取最边缘右端点 55 { 56 mid=(l+r)/2; 57 ma=RMQ(i,mid,0); 58 mb=RMQ(i,mid,1); 59 60 if(ma>mb) r=mid-1; 61 else 62 { 63 if(ma==mb) en=mid; 64 l=mid+1; 65 } 66 } 67 sum+=(en-st+1); 68 } 69 printf("%lld\n",sum); 70 return 0; 71 }
还有一种方法
利用双端队列(即两端都可以插入和删除),即deque
源代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[200010],b[200010]; 4 long long sum=0; 5 int main() 6 { 7 int n; 8 scanf("%d",&n); 9 for(int i=1;i<=n;i++) 10 scanf("%d",&a[i]); 11 for(int i=1;i<=n;i++) 12 scanf("%d",&b[i]); 13 deque<int>x,y; 14 for(int i=1,j=1;i<=n;i++) 15 { 16 while(!x.empty()&&a[x.back()]<=a[i]) x.pop_back(); 17 while(!y.empty()&&b[y.back()]>=b[i]) y.pop_back(); 18 x.push_back(i); 19 y.push_back(i); 20 while(j<=i&&(a[x.front()]-b[y.front()]>0)) 21 { 22 j++; 23 while(!x.empty()&&x.front()<j) x.pop_front(); 24 while(!y.empty()&&y.front()<j) y.pop_front(); 25 } 26 if(!x.empty()&&!y.empty()&&a[x.front()]==b[y.front()]) 27 sum+=min(x.front(),y.front())-j+1; 28 } 29 printf("%lld\n",sum); 30 return 0; 31 }