时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
链接:https://ac.nowcoder.com/acm/contest/881/A
来源:牛客网
题目描述
Two arrays u and v each with m distinct elements are called equivalent if and only if RMQ(u,l,r)=RMQ(v,l,r)RMQ(u,l,r)=RMQ(v,l,r) for all 1≤l≤r≤m1≤l≤r≤m
where RMQ(w,l,r)RMQ(w,l,r) denotes the index of the minimum element among wl,wl+1,…,wrwl,wl+1,…,wr.
Since the array contains distinct elements, the definition of minimum is unambiguous.
Bobo has two arrays a and b each with n distinct elements. Find the maximum number p≤np≤n where {a1,a2,…,ap}{a1,a2,…,ap} and {b1,b2,…,bp}{b1,b2,…,bp} are equivalent.
输入描述:
The input consists of several test cases and is terminated by end-of-file.
The first line of each test case contains an integer n.
The second line contains n integers a1,a2,…,ana1,a2,…,an.
The third line contains n integers b1,b2,…,bnb1,b2,…,bn.
* 1≤n≤1051≤n≤105
* 1≤ai,bi≤n1≤ai,bi≤n
* {a1,a2,…,an}{a1,a2,…,an} are distinct.
* {b1,b2,…,bn}{b1,b2,…,bn} are distinct.
* The sum of n does not exceed 5×1055×105.
输出描述:
For each test case, print an integer which denotes the result.
输入
2 1 2 2 1 3 2 1 3 3 1 2 5 3 1 5 2 4 5 2 4 3 1
输出
1 3 4
题目大意:给出两个序列A和B,让你找出最大的一个p,使得在区间[1,p]内,任意的l,r∈[1,n],
RMQ(l,r,A)要等于RMQ(l,r,B)。RMQ(l,r,A)返回的是[l,r]内最小值对应的下标。
例如:序列A为1,4,5,2。RMQ(2,4,A)的值为4
一开始理解错题意,理解成了找最大的p,使得RMQ(1,q,A)=RMQ(1,q,B),队友奔着这个思路WA了8次。
后来别人在打线段树的时候,我在想别的做法(其实是懒得打)
那就是——单调栈(手动滑稽,比赛时我叫它单调队列)!
接下来让我们来推理(yy)一波:
对于序列A和序列B,
1. 首先考虑r-l+1=2,即区间长度为2的情况。要满足A和B在这段区间的RMQ值相等,那么一定满足a[l]<a[r]同时b[l]<b[r],或者a[l]>a[r]同时b[l]>b[r]。
2. 考虑区间长度为3的情况,
当a[l]<a[l+1]<a[l+2],b[l]<b[l+1]<b[l+2]时,满足第一种情况。
当a[l]<a[l+1],a[l+1]>a[l+2],b[l]<b[l+1],b[l+1]>b[l+2]时,我们会发现这时需要比较a[l]和a[l+2]和b[l]和b[l+2]两者的大小关系,即单调性一致。无论中间加了多少个比这两者大的数,都需要对这两者的大小关系进行比较,因为这两个数有一个是最小值,所以会影响这段区间的RMQ值
而当中间插入了比两端小的数,即a[l]>a[l+1],a[l+1]<a[l+2],b[l]>b[l+1],b[l+1]<b[l+2]时,我们会发现这时候的a[l]和b[l]对以后的区间的RMQ是没有影响的,这个时候我们可以把它pop掉,这样模拟下去,那么就会很容易的想到单调栈这个东西啦。
于是推理结束。
后来发现好多人用线段树,过意不去也做了一遍。
--------------------------------------------------------
单调栈做法O(N):
语言:C++ 代码长度:1426 运行时间:72ms 占用内存:5112KB
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define numm ch-48 3 #define pd putchar(' ') 4 #define pn putchar(' ') 5 #define pb push_back 6 #define mp make_pair 7 #define fi first 8 #define se second 9 #define fi first 10 #define se second 11 #define fre1 freopen("1.txt","r",stdin) 12 #define fre2 freopen("2.txt","w",stdout) 13 using namespace std; 14 template <typename T> 15 void read(T &res) { 16 bool flag=false;char ch; 17 while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true); 18 for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm); 19 flag&&(res=-res); 20 } 21 template <typename T> 22 void write(T x) { 23 if(x<0) putchar('-'),x=-x; 24 if(x>9) write(x/10); 25 putchar(x%10+'0'); 26 } 27 28 typedef long long ll; 29 typedef long double ld; 30 const ll mod=1e9+7; 31 const int maxn=1e5+5; 32 const int inf=0x3f3f3f3f; 33 const int INF=0x7fffffff; 34 stack<int>s1,s2; 35 int a[maxn],b[maxn]; 36 int main() 37 { 38 int n; 39 while(scanf("%d",&n)!=EOF) { 40 for(int i=1;i<=n;i++) 41 read(a[i]); 42 for(int i=1;i<=n;i++) 43 read(b[i]); 44 while(!s1.empty()) s1.pop(); 45 while(!s2.empty()) s2.pop(); 46 int ans=n; 47 for(int i=1;i<=n;i++) { 48 while(!s1.empty()&&a[i]<s1.top()) s1.pop(); 49 while(!s2.empty()&&b[i]<s2.top()) s2.pop(); 50 s1.push(a[i]),s2.push(b[i]); 51 if(s1.size()!=s2.size()) { 52 ans=i-1; 53 break; 54 } 55 } 56 write(ans);pn; 57 } 58 return 0; 59 }
二分+递归+线段树查最小值下标是否相等做法:
语言:C++ 代码长度:3161 运行时间:572ms 占用内存:13412KB
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define numm ch-48 3 #define pd putchar(' ') 4 #define pn putchar(' ') 5 #define pb push_back 6 #define mp make_pair 7 #define fi first 8 #define se second 9 #define fi first 10 #define se second 11 #define fre1 freopen("1.txt","r",stdin) 12 #define fre2 freopen("2.txt","w",stdout) 13 using namespace std; 14 template <typename T> 15 void read(T &res) { 16 bool flag=false;char ch; 17 while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true); 18 for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm); 19 flag&&(res=-res); 20 } 21 template <typename T> 22 void write(T x) { 23 if(x<0) putchar('-'),x=-x; 24 if(x>9) write(x/10); 25 putchar(x%10+'0'); 26 } 27 const int maxn=1e5+5; 28 typedef long long ll; 29 typedef long double ld; 30 const ll mod=1e9+7; 31 const int inf=0x3f3f3f3f; 32 const int INF=0x7fffffff; 33 struct node { 34 int index; 35 int l,r; 36 int minn; 37 }tree1[maxn<<2],tree2[maxn<<2]; 38 int n; 39 int a[maxn],b[maxn]; 40 inline int ls(int k) { 41 return k<<1; 42 } 43 inline int rs(int k) { 44 return k<<1|1; 45 } 46 inline void PushUp(int k) { 47 if(tree1[ls(k)].minn>tree1[rs(k)].minn) { 48 tree1[k].minn=tree1[rs(k)].minn; 49 tree1[k].index=tree1[rs(k)].index; 50 } 51 else { 52 tree1[k].minn=tree1[ls(k)].minn; 53 tree1[k].index=tree1[ls(k)].index; 54 } 55 if(tree2[ls(k)].minn>tree2[rs(k)].minn) { 56 tree2[k].minn=tree2[rs(k)].minn; 57 tree2[k].index=tree2[rs(k)].index; 58 } 59 else { 60 tree2[k].minn=tree2[ls(k)].minn; 61 tree2[k].index=tree2[ls(k)].index; 62 } 63 return ; 64 } 65 inline void build(int l,int r,int k) { 66 tree1[k].l=l; 67 tree1[k].r=r; 68 tree2[k].l=l; 69 tree2[k].r=r; 70 if(l==r) { 71 tree1[k].index=l; 72 tree1[k].minn=a[l]; 73 tree2[k].index=l; 74 tree2[k].minn=b[l]; 75 return ; 76 } 77 int mid=(l+r)>>1; 78 build(l,mid,ls(k)); 79 build(mid+1,r,rs(k)); 80 PushUp(k); 81 } 82 int QueryA(int A,int B,int l,int r,int k) { 83 if(B<l||A>r) return 0; 84 if(A<=l&&r<=B) return tree1[k].index; 85 int mid=(l+r)>>1; 86 int ans=0; 87 int temp=QueryA(A,B,l,mid,ls(k)); ///左边 88 if(a[ans]>a[temp]) 89 ans=temp; 90 temp=QueryA(A,B,mid+1,r,rs(k)); ///右边 91 if(a[ans]>a[temp]) 92 ans=temp; 93 return ans; 94 } 95 int QueryB(int A,int B,int l,int r,int k) { 96 if(B<l||A>r) return 0; 97 if(A<=l&&r<=B) return tree2[k].index; 98 int mid=(l+r)>>1; 99 int ans=0; 100 int temp=QueryB(A,B,l,mid,ls(k)); 101 if(b[ans]>b[temp]) 102 ans=temp; 103 temp=QueryB(A,B,mid+1,r,rs(k)); 104 if(b[ans]>b[temp]) 105 ans=temp; 106 return ans; 107 } 108 bool DfsJudge(int l,int r) { 109 if(l>=r) return true; 110 int minposa=QueryA(l,r,1,n,1); 111 int minposb=QueryB(l,r,1,n,1); 112 if(minposa!=minposb) return false; 113 return DfsJudge(l,minposa-1)&&DfsJudge(minposa+1,r); 114 } 115 inline int solve() { 116 int l=1,r=n,ans=1; 117 while(l<=r) { 118 int mid=(l+r)>>1; 119 if(DfsJudge(1,mid)) ans=mid,l=mid+1; 120 else r=mid-1; 121 } 122 return ans; 123 } 124 int main() 125 { 126 a[0]=b[0]=inf; 127 while(scanf("%d",&n)!=EOF) { 128 for(int i=1;i<=n;i++) 129 read(a[i]); 130 for(int i=1;i<=n;i++) 131 read(b[i]); 132 build(1,n,1); 133 write(solve());pn; 134 } 135 return 0; 136 }