【2019牛客暑期多校训练营(第一场) - A】Equivalent Prefixes(单调栈,tricks)

题干:

链接: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)

for all 1≤l≤r≤m
where RMQ(w,l,r) denotes the index of the minimum element among 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≤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

题目大意:

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

解题报告:

首先不难证明p是具有单调性的,换句话说,假设p=x成立,那么对任意p=1,2,3...x都成立。(因为他求的区间个数是绝对递增的而且是完全包含之前的区间的)

那么运用数学归纳法的思维,先假设p=i成立,那么当p=i+1时,要考虑的区间就是左端点1~i,右端点i+1。先只考察一个数组的时候,很显然能发现的一个问题就是,因为这个题目只关心最小值,所以区间的左端点从i到1变化的时候,如果变化到j了发现a[j] < a[i+1],则左端点<=j那些区间肯定都不用看了(因为最小值与a[i+1]无关,也就是此时【左端点,i+1】的情况和【左端点,i】的情况相同,又因为假设了p=i成立,所以那些区间肯定成立)。换句话说,a[i+1]只承担左端点为j+1~i的最小值。

回到这个题目,所以只需要比较对于每个p,两个数组求出的j的值是否相同就可以了,如果不相同的话一定就GG。(找交叉部分的区间的某个点当左端点就一定不行)。再把问题抽象一下,就是要看每个点左侧第一个比他小的点是否下标相同就可以了。

问题化简到这里就很显然了,思路就是单调栈。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
const int INF = 0x3f3f3f3f;
int la[MAX],lb[MAX],a[MAX],b[MAX],n;
stack<int> sa,sb;
int main()
{
	while(~scanf("%d",&n)) {
		for(int i = 1; i<=n; i++) scanf("%d",a+i);
		for(int i = 1; i<=n; i++) scanf("%d",b+i);
		while(sa.size()) sa.pop();
		for(int i = 1; i<=n; i++) {
			while(sa.size() && a[i] < a[sa.top()]) sa.pop();
			if(sa.empty()) la[i] = 0;
			else la[i] = sa.top();
			sa.push(i);
		}
		while(sb.size()) sb.pop();
		for(int i = 1; i<=n; i++) {
			while(sb.size() && b[i] < b[sb.top()]) sb.pop();
			if(sb.empty()) lb[i] = 0;
			else lb[i] = sb.top();
			sb.push(i);
		}
		int ans = 0;
		for(int i = 1; i<=n; i++) {
			if(la[i] == lb[i]) ans = i;
			else break;
		}
		printf("%d\n",ans);
	}
	return 0 ;
}

注意一个小细节:最后判断的时候,不能这么写,不然还得特判当没有break的时候,ans=n。或者直接赋初值ans=n。

for(int i = 1; i<=n; i++) {
	if(la[i] != lb[i]) {
		ans = i-1;break;
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值