2019牛客暑期多校训练营(第一场) A Equivalent Prefixes(单调栈/二分+递归+线段树)

时间限制: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.

* 1n1051≤n≤105
* 1ai,bin1≤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

 1 #include<bits/stdc++.h>
 2 #define numm ch-48
 3 #define pd putchar(' ')
 4 #define pn putchar('\n')
 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

  1 #include<bits/stdc++.h>
  2 #define numm ch-48
  3 #define pd putchar(' ')
  4 #define pn putchar('\n')
  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 }
代码在这里!

 

posted @ 2019-07-23 14:54  wuliking  阅读(190)  评论(0)    收藏  举报