链接: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. @codeforces - 932G@ Palindrome Partition

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个字符串 s,求有多少种方案可将其划分成偶数个段 \(p_ ...

  2. win10下Anaconda3配置环境变量

    有时候在win10安装好Anaconda3后,使用conda命令时依然会出现: C:\Users\dell\PycharmProjects\pytorch>conda list 'conda' ...

  3. oralce使用INSERT语句向表中插入数据

    INSERT   INTO    table[ (column [, column. . .])] VALUES            (value [,value . . .]); v  插入的数据 ...

  4. CPU核数和线程数查找

    方法1: 方法2:

  5. 2017 ACM-ICPC 亚洲区(南宁赛区)网络赛 M. Frequent Subsets Problem【状态压缩】

    2017 ACM-ICPC 亚洲区(南宁赛区)网络赛  M. Frequent Subsets Problem 题意:给定N和α还有M个U={1,2,3,...N}的子集,求子集X个数,X满足:X是U ...

  6. UVa 10599【lis dp,记忆化搜索】

    UVa 10599 题意: 给出r*c的网格,其中有些格子里面有垃圾,机器人从左上角移动到右下角,只能向右或向下移动.问机器人能清扫最多多少个含有垃圾的格子,有多少中方案,输出其中一种方案的格子编号. ...

  7. Windows命令行创建计划任务

    Windows上创建计划任务,尽管可以通过控制面板中的"计划任务"来创建,但是,有可能会报错: 这时,可以在cmd中使用命令行工具schtasks来创建.比如想要创建一个名为&qu ...

  8. 实时计算轻松上手,阿里云DataWorks Stream Studio正式发布

    Stream Studio是DataWorks旗下重磅推出的全新子产品.已于2019年4月18日正式对外开放使用.Stream Studi是一站式流计算开发平台,基于阿里巴巴实时计算引擎Flink构建 ...

  9. 初识block

    我们可以把Block当做Objective-C的匿名函数.Block允许开发者在两个对象之间将任意的语句当做数据进行传递,往往这要比引用定义在别处的函数直观.另外,block的实现具有封闭性(clos ...

  10. python selenium 测试浏览器(IE,FF,Chrome)

    browser_engine.py # coding=utf-8 from selenium import webdriver class BrowserEngine(object): "& ...