Codeforces 1142B Lynyrd Skynyrd

Codeforces 1142B Lynyrd Skynyrd

题目链接

https://codeforces.com/problemset/problem/1142/B

题目大意

给你一个排列 $P$ 和一个数组 $A$ ,$Q$ 次询问,每次询问 $A$ 在 $[l, r]$ 之间是否存在一个子串,在循环平移之后和 $P$ 相同。

题目分析

定义 $f[i]$ 为数字 $i$ 的最大的出现位置从 $1$ 到 $n$ 进行 $DP$ ,记录下每一个元素在 $P$ 中的前驱的最大出现位置。统计完成之后再使用倍增,处理所有的元素往前找能找到的元素。随后,对于每一个位置,统计出来由它开始往前能构造出来的 $P$ 的最大起始位置。随后 $O(1)$ 查询即可。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

const int maxn = 2e5 + 5;

int n, m, q, t;

int a[maxn];
int b[maxn];

int fa[maxn][20];

int f[maxn];
int ans[maxn];
int last[maxn];

int read(){
	int x;
	scanf("%d", &x);
	return x;
}

int main(){
	int i, j;
	int l, r;
	
	n = read();
	m = read();
	q = read();
	
	for(i=1;i<=n;i++){
		a[i] = read();
		last[a[i]] = a[i - 1];
	}
	last[a[1]] = a[n];
	
	for(i=1;i<=m;i++){
		b[i] = read();
	}
	
	for(i=1;i<=m;i++){
		fa[i][0] = f[last[b[i]]];
		f[b[i]] = i;
	}
	
	for(i=1;i<=m;i++){
		for(j=0;fa[fa[i][j]][j];j++){
			fa[i][j + 1] = fa[fa[i][j]][j];
		}
	}
	
	for(i=1;i<=m;i++){
		ans[i] = i;
		int x = n - 1;
		for(j=20;j>=0;j--){
			if(x >= (1 << j)){
				ans[i] = fa[ans[i]][j];
				x -= (1 << j);
			}
		}
		ans[i] = max(ans[i], ans[i - 1]);
	}
	
	while(q--){
		l = read();
		r = read();
		
		if(ans[r] >= l){
			printf("1");
		}else{
			printf("0");
		}
	}
	
	printf("\n");
	
	return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据