2019牛客暑期多校训练营(第一场) A Equivalent Prefixes ( st 表 + 二分+分治)

链接:https://ac.nowcoder.com/acm/contest/881/A

来源:牛客网

Equivalent Prefixes

时间限制:C/C++ 2秒,其他语言4秒

空间限制:C/C++ 524288K,其他语言1048576K

64bit IO Format: %lld

题目描述

Two arrays u and v each with m distinct elements are called equivalent if and only if

R

M

Q

(

u

,

l

,

r

)

R

M

Q

(

v

,

l

,

r

)

RMQ(u,l,r)=RMQ(v,l,r) for all

1



l



r



m

1≤l≤r≤m

where

R

M

Q

(

w

,

l

,

r

)

RMQ(w,l,r) denotes the index of the minimum element among

w

l

,

w

l

+

1

,



,

w

r

wl,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



n

p≤n where

{

a

1

,

a

2

,



,

a

p

}

{a1,a2,…,ap} and

{

b

1

,

b

2

,



,

b

p

}

{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

a

1

,

a

2

,



,

a

n

a1,a2,…,an.

The third line contains n integers

b

1

,

b

2

,



,

b

n

b1,b2,…,bn.

1



n



10

5

1≤n≤105

*

1



a

i

,

b

i



n

1≤ai,bi≤n

*

{

a

1

,

a

2

,



,

a

n

}

{a1,a2,…,an} are distinct.

*

{

b

1

,

b

2

,



,

b

n

}

{b1,b2,…,bn} are distinct.

  • The sum of n does not exceed

    5

    ×

    10

    5

    5×105.

    输出描述:

    For each test case, print an integer which denotes the result.

    示例1

    输入

    复制

    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,大小为n,让你寻找一个数p (1<= p <= n) ,使之在 1~p 任意一个区间中a,b数组的最小值下标相同。

思路:

容易知道p的取值具有单调性,首先我们用st表在对数组a,b进行预处理,方便后续的RMQ,因为数组中的数相互不同,那么我们就可以直接RMQ获得区间最小值下标。

在二分p的过程中,我们这样来判断mid是否合法:

询问1~mid 区间两个数组中的最小值下标是否一致,如果不一致直接返回false,否则 以最小值下标minid为分界点递归处理1minid,minid+1mid。这个过程是O(n)的

所以总体时间复杂度是 O( n* log n )

细节见代码:

#include<iostream>
using namespace std;
const int maxn=2e5+10;
int n;
int a[maxn],b[maxn];
int sa[maxn][20],sb[maxn][20],mn[maxn];
void init()
{
mn[0]=-1;
for (int i=1;i<=n;i++)
{
mn[i]=((i & (i-1))==0) ? mn[i-1]+1 : mn[i-1];
sa[i][0]=a[i];
sb[i][0]=b[i];
}
for (int j=1;j<=mn[n];j++)
for (int i=1;i+(1<<j)-1<=n;i++)
{
sa[i][j]=min(sa[i][j-1],sa[i+(1<<(j-1))][j-1]);
sb[i][j]=min(sb[i][j-1],sb[i+(1<<(j-1))][j-1]);
}
}
int ida[maxn];
int idb[maxn];
int rqa(int L,int R)
{
int k=mn[R-L+1];
// cout<<"a "<<min(sa[L][k],sa[R-(1<<k)+1][k])<<endl;
return ida[min(sa[L][k],sa[R-(1<<k)+1][k])];
}
int rqb(int L,int R)
{
int k=mn[R-L+1];
// cout<<"b "<<min(sb[L][k],sb[R-(1<<k)+1][k])<<endl;
return idb[min(sb[L][k],sb[R-(1<<k)+1][k])];
}
bool pan(int l,int r)
{
if(l>=r)
{
return 1;
}
int w=rqb(l,r);
int q=rqa(l,r);
if(w!=q)
{
return 0;
}else{
return pan(l,w-1)&&(pan(q+1,r));
}
}
bool check(int mid)
{
// bool res=1;
return pan(1,mid);
}
int main(){
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
ida[a[i]]=i;
}
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
idb[b[i]]=i;;
}
init();
int l=1;
int r=n;
int mid;
int ans=1;
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid))
{
l=mid+1;
ans=mid;
}else{
r=mid-1;
} }
printf("%d\n",ans);
}
}
上一篇:Vulkan Tutorial 18 重构交换链


下一篇:小心踩雷,一次Java内存泄漏排查实战