P7333 [JRKSJ R1] JFCA 题解

发布时间 2023-07-17 14:02:28作者: JJL0610

前言

传送门

blog

思路

首先看数据范围 $10^5$,$O(n \log_2 n)$ 可以过,自然想到二分

二分具有单调性,那么如何确保整个 $a$ 序列按顺序排列呢?

我们可以使用 st 表维护区间最大值,如果在这个距离中已经有了 $a_i\ge b_j$ 那么最大值一定指向的是新加入进来的那个值,否则在之前二分就已经不会再继续扩展了。

对于环形结构我们必须断环为链,这样可以将环形变为链形,并且保证答案的正确性。

这时我们就必须要考虑二分断环为链了,因为二分会向右扩展 $mid$,所以两倍会越界,那么就需要开三倍。

那么我们如何判断无解呢?在 $l = n$ 时说明已经过了一圈但是还是没有找到 $a_i\ge b_j$,又回到了 $j$,说明无解。

#include <bits/stdc++.h>
using namespace std;

int n,a[300010],LOG2[300010],st[300010][30];

inline int read()
{
	int x = 0,f = 1;char ch = getchar();
	while (ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
	while (ch >= '0' && ch <= '9'){x = x * 10 + ch - 48;ch = getchar();}
	return x * f;
}

void init(){
	for(int i = 2;i <= 3 * n;i++)
		LOG2[i] = LOG2[i >> 1] + 1; 
	for(int i = 1;i <= n;i++)
		st[i][0] = st[i + n][0] = st[i + n + n][0] = a[i];
	int k = LOG2[3 * n];
	for(int i = 1;i <= k;i++)
		for(int j = 1;j + (1 << i) - 1 <= 3 * n;j++){
			st[j][i] = max(st[j][i - 1],st[j + (1 << i - 1)][i - 1]); 
		}	
}	

int num(int l,int r){
	int s = LOG2[r - l + 1];
	int x = max(st[l][s],st[r - (1 << s) + 1][s]);
	return x; 
}

int two(int x,int y){
	int l = 1,r = n;
	while(l < r){
		int mid = (l + r) >> 1;
		if(max(num(y - mid,y - 1),num(y + 1,y + mid)) >= x)
			r = mid;
		else
			l = mid + 1;
	}
	return l == n ? -1 : l;
} 

int main(){
	n = read(); 
	for(int i = 1;i <= n;++i)
		a[i] = read();
	init();
	for(int i = 1;i <= n;i++){
		int b = read();
		printf("%d ",two(b,i + n));
	}
	return 0;
}