• 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('
    ')
     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('
    ')
      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 }
    代码在这里!
  • 相关阅读:
    Visual SVN1.5以上版本下载及破解过程
    C#线程系列讲座(2):Thread类的应用
    a标签的href 和onclick
    Windows 服务快捷启动命令
    iframe 跨域自动适应高度
    修正认知:string、Empty和null三者的正确区别

    线索二叉树
    最大连续子序列
    寻找最近点对
  • 原文地址:https://www.cnblogs.com/wuliking/p/11231774.html
Copyright © 2020-2023  润新知