链接: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.
示例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 题意:
两个长度为n的数组,求最大的m,使得1到m之内的所有区间的最小值位置相同。
思路:
单调栈:
记录每个值的左边第一个比当前值小的位置。
从左到右遍历一遍,记录下第一个单调栈结果不同的地方,该位置前一个位置就是答案。
证明:
如果你确认了位置i是正确的,并且单调栈记录的位置是pos,那么(pos,i),(pos+1,i)... (i,i)都是符合条件的。
如果pos左侧的值都比pos处的值要大,那么显而易见,(1,i),(2,i),...,(pos-1,i)也是符合题意的。
如果pos左侧的值有比pos处的值小的,那么从右边数,第一个比pos小的值的位置pos2,对于两个数组,也一定相等,(因为之前已经检测过pos了,不然也不会走到i)
那么(pos2+1,i),(pos2+2,i)...(pos-1,i)也是符合题意的。
再从pos2开始考虑,用类似递归的思想,很容易明白,(1,i),(2,i),...,(pos-1,i)都是符合题意的。
这是右端点是i的情况,但是因为i从左向右遍历,所以之前的所有区间其实都已经检测过了。 再考虑不相等的情况:
如果在位置i,第一个数组从右向左的第一个位置为pos1,第二个是pos2,且pos1<pos2
那么对于第一个数组,(pos2,i)的最小值位置是i,对于第一个数组,(pos2,i)的最小值位置是pos2,显然不同。
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime> #define fuck(x) cerr<<#x<<" = "<<x<<endl;
#define debug(a, x) cerr<<#a<<"["<<x<<"] = "<<a[x]<<endl;
#define ls (t<<1)
#define rs ((t<<1)|1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = ;
const int maxm = ;
const int inf = 0x3f3f3f3f;
const ll Inf = ;
const int mod = ;
const double eps = 1e-;
const double pi = acos(-); int num1[maxn],num2[maxn];
int ans1[maxn],ans2[maxn];
struct node{
int num,id;
};
stack<node>st;
int main() {
// ios::sync_with_stdio(false);
// freopen("in.txt", "r", stdin); int n;
while (scanf("%d",&n)!=EOF){
for(int i=;i<=n;i++){
scanf("%d",&num1[i]);
}
for(int i=;i<=n;i++){
scanf("%d",&num2[i]);
}
num1[]=num2[]=-;
int ans=n;
for(int i=n;i>=;i--){
while (!st.empty()&&st.top().num>num1[i]){
ans1[st.top().id]=i;
st.pop();
}st.push(node{num1[i],i});
}for(int i=n;i>=;i--){
while (!st.empty()&&st.top().num>num2[i]){
ans2[st.top().id]=i;
st.pop();
}st.push(node{num2[i],i});
}for(int i=;i<=n;i++){
if(ans1[i]!=ans2[i]){
ans=i-;
break;
}
}printf("%d\n",ans); } return ;
}
二分+分治
如果位置p符合题意,那么pos<p也一定满足题意。
那么现在在check区间l,r是否满足题意。
如果区间(l,r)两个数组最小值位置都是pos,那么对于区间(L,R) l<=L<pos,r>=R>pos,最小值位置就是pos.
所以只需要考虑L,R都在pos同一边即可。
于是就是pos为分界线进行分治。
如果区间(l,r)两个数组最小值位置不同,直接返回false
#include <set>
#include <map>
#include <cmath>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = + ;
const int INF = 0x3f3f3f3f;
int a[maxn], b[maxn];
int pos1[maxn], pos2[maxn];
int st1[maxn][];
int n; void rmq_init1() {
for (int i = ; i <= n; i++) {
st1[i][] = a[i];
}
int l = ;
for (int i = ; l <= n; i++) {
for (int j = ; j + l / <= n; j++) {
st1[j][i] = min(st1[j][i - ], st1[j + l / ][i - ]);
}
l <<= ;
}
}
int ask_min1(int i, int j) {
int k = int(log(j - i + 1.0) / log(2.0));
return min(st1[i][k], st1[j - ( << k) + ][k]);
} int st2[maxn][]; void rmq_init2() {
for (int i = ; i <= n; i++) {
st2[i][] = b[i];
}
int l = ;
for (int i = ; l <= n; i++) {
for (int j = ; j + l / <= n; j++) {
st2[j][i] = min(st2[j][i - ], st2[j + l / ][i - ]);
}
l <<= ;
}
}
int ask_min2(int i, int j) {
int k = int(log(j - i + 1.0) / log(2.0));
return min(st2[i][k], st2[j - ( << k) + ][k]);
}
bool check(int l,int r){
// cout<<l<<" "<<r<<endl;
if(l>=r) return true;
int min1=ask_min1(l,r);
int min2=ask_min2(l,r);
int p1=pos1[min1];
int p2=pos2[min2];
if(p1==p2) {
return check(l,p1-)&&check(p1+,r);
}else{
return false;
}
}
int main() { while(scanf("%d", &n) != EOF) { for(int i = ; i <= n; i++) {
scanf("%d", &a[i]);
pos1[a[i]] = i;
}
for(int i = ; i <= n; i++) {
scanf("%d", &b[i]);
pos2[b[i]] = i;
}
rmq_init1();
rmq_init2();
int l=,r=n;
int ans=;
while(l<=r){
int mid=(l+r)>>;
if(check(,mid)){
ans=mid;
l=mid+;
}else{
r=mid-;
}
}
printf("%d\n",ans);
}
return ;
}

那些n方复杂度过的大佬,可以看一下如果数据是两个1e5的单调递增/递减数组,你们的代码会不会出事。

推广:https://blog.nowcoder.net/n/zgq

2019牛客暑期多校训练营(第一场)A Equivalent Prefixes(单调栈/二分+分治)的更多相关文章

  1. 2019 牛客暑期多校 第八场 A All-one Matrices (单调栈+前缀和)

    题目:https://ac.nowcoder.com/acm/contest/888/A 题意:找全1矩阵的个数,并且这个全1矩阵不被其他全1矩阵包含 思路:这里引用付队说的话 -> { 这类问 ...

  2. 2019牛客暑期多校训练营(第二场) H-Second Large Rectangle(单调栈)

    题意:给出由01组成的矩阵,求求全是1的次大子矩阵. 思路: 单调栈 全是1的最大子矩阵的变形,不能直接把所有的面积存起来然后排序取第二大的,因为次大子矩阵可能在最大子矩阵里面,比如: 1 0 0 1 ...

  3. 2019牛客暑期多校训练营(第九场) D Knapsack Cryptosystem

    题目 题意: 给你n(最大36)个数,让你从这n个数里面找出来一些数,使这些数的和等于s(题目输入),用到的数输出1,没有用到的数输出0 例如:3  4 2 3 4 输出:0 0 1 题解: 认真想一 ...

  4. 2019 牛客暑期多校 第三场 F Planting Trees (单调队列+尺取)

    题目:https://ac.nowcoder.com/acm/contest/883/F 题意:求一个矩阵最大面积,这个矩阵的要求是矩阵内最小值与最大值差值<=m 思路:首先我们仔细观察范围,我 ...

  5. 2019牛客暑期多校训练营(第五场)G - subsequeue 1 (一题我真的不会的题)

    layout: post title: 2019牛客暑期多校训练营(第五场)G - subsequeue 1 (一题我真的不会的题) author: "luowentaoaa" c ...

  6. 牛客多校第一场 A Equivalent Prefixes 单调栈(笛卡尔树)

    Equivalent Prefixes 单调栈(笛卡尔树) 题意: 给出两个数组u,v,每个数组都有n个不同的元素,RMQ(u,l,r)表示u数组中[l,r]区间里面的最小值标号是多少,求一个最大的m ...

  7. 2019牛客暑期多校训练营(第一场)A题【单调栈】(补题)

    链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 题目描述 Two arrays u and v each with m distinct elem ...

  8. 2019牛客暑期多校训练营(第一场)-A (单调栈)

    题目链接:https://ac.nowcoder.com/acm/contest/881/A 题意:给定两个长度均为n的数组a和b,求最大的p使得(a1,ap)和(b1,bp)等价,等价的定义为其任意 ...

  9. 2019牛客暑期多校训练营(第一场) B Integration (数学)

    链接:https://ac.nowcoder.com/acm/contest/881/B 来源:牛客网 Integration 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 5242 ...

随机推荐

  1. 写一个nginx监控日志

    下面的代码是实现一个nginx监控日志功能,是不是很好玩呢.

  2. Kafka Connect HDFS

    概述 Kafka 的数据如何传输到HDFS?如果仔细思考,会发现这个问题并不简单. 不妨先想一下这两个问题? 1)为什么要将Kafka的数据传输到HDFS上? 2)为什么不直接写HDFS而要通过Kaf ...

  3. hdu5131 贪心

    #include<stdio.h> #include<string.h> #include<algorithm> #include<string> #i ...

  4. BZOJ 1008 越狱题解

    其实这题很水,显然n个房间有m种宗教,总共有n^m种情况, 我们再考虑不合法的情况,显然第一个房间有m种情况,而后一种只有m-1种情况(因为不能相同) 所以不合法的情况有(m-1)^(n-1)*m种情 ...

  5. 【NS2】How to remove Cygwin completely from Windows

    How to remove Cygwin completely from Windows 9th September 2012. 31243 views. Software Remember need ...

  6. vim删除行

    0,vim filename 1,显示行号 :set number 2,跳转到第1000行 1000G (跳转到文件末尾:“G”) 3,删除1-1000行 :1,.d 4,删除所有行 先跳转到文件最后 ...

  7. HDU 5673 Robot【卡特兰数】

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5673 题意: 有一个机器人位于坐标原点上.每秒钟机器人都可以向右移到一个单位距离,或者在原地不动.如 ...

  8. Java练习 SDUT-1704_统计数字问题

    统计数字问题 Time Limit: 1000 ms Memory Limit: 32768 KiB Problem Description 一本书的页码从自然数1 开始顺序编码直到自然数n.书的页码 ...

  9. Flask学习之四 数据库

    英文博客地址:http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-iv-database 中文翻译地址:http://ww ...

  10. Hadoop及HIVE学习宝典收集

    Hive经常使用命令https://cwiki.apache.org/confluence/display/Hive/GettingStartedhttp://richardxu.com/hiveql ...