CodeForces-1143E Lynyrd Skynyrd(倍增)

Description:
Recently Lynyrd and Skynyrd went to a shop where Lynyrd bought a permutation p of length n, and Skynyrd bought an array a of length m, consisting of integers from 1 to n.

Lynyrd and Skynyrd became bored, so they asked you q queries, each of which has the following form: “does the subsegment of a from the l-th to the r-th positions, inclusive, have a subsequence that is a cyclic shift of p?” Please answer the queries.

A permutation of length n is a sequence of n integers such that each integer from 1 to n appears exactly once in it.

A cyclic shift of a permutation (p1,p2,…,pn) is a permutation (pi,pi+1,…,pn,p1,p2,…,pi−1) for some i from 1 to n. For example, a permutation (2,1,3) has three distinct cyclic shifts: (2,1,3), (1,3,2), (3,2,1).

A subsequence of a subsegment of array a from the l-th to the r-th positions, inclusive, is a sequence ai1,ai2,…,aik for some i1,i2,…,ik such that l≤i1<i2<…<ik≤r.
Input
The first line contains three integers n, m, q (1≤n,m,q≤2e5) — the length of the permutation p, the length of the array a and the number of queries.

The next line contains n integers from 1 to n, where the i-th of them is the i-th element of the permutation. Each integer from 1 to n appears exactly once.

The next line contains m integers from 1 to n, the i-th of them is the i-th element of the array a.

The next q lines describe queries. The i-th of these lines contains two integers li and ri (1≤li≤ri≤m), meaning that the i-th query is about the subsegment of the array from the li-th to the ri-th positions, inclusive.

Output
Print a single string of length q, consisting of 0 and 1, the digit on the i-th positions should be 1, if the subsegment of array a from the li-th to the ri-th positions, inclusive, contains a subsequence that is a cyclic shift of p, and 0 otherwise.

Examples
input
3 6 3
2 1 3
1 2 3 1 2 3
1 5
2 6
3 5
output
110
input
2 4 3
2 1
1 1 2 2
1 2
2 3
3 4
output
010

题意:给你一个排列P,再给你一个数组A,对于每个查询[L,R],问AL到AR这段序列有没有子序列B使得B是排列P循环右移得到的序列。(2,1,3)的循环右移能得到的序列有(2,1,3),(1,3,2),(3,2,1)
题解:对于A中的每一个Ai,求出 (Ai在P中的前一个数字)在A中的小于i的最大位置b[i]。比如P是(3,2,1),A是(3,1,2,3),那对于A中的2来说,求出来的b就是1,对于A中第二个3来说,求出来的b就是2,得到的b为(0,0,1,2)。可以通过记录每一个数字最后出现的位置来求每一个Ai的b[i]。
那对于一个A[i],我们算b[b[b[b[…b[i]]…],套n-1次就可以得到[L,i]这个区间存在以A[i]为结尾的循环右移排列需要的最大的L。直接套的话每一个数字都要算N-1次,是O(n²)的算法,所以我们用倍增的思想,f[i][j]代表第i个数字要得到以它为结尾的长度为2^j的排列所需要的最大的区间左端点L,那么显然f[i][0] = b[i],转移方程为f[i][j+1] = f[ f[i][j] ] [ j ],
然后用g[i]表示最大的L使得[L,i]这个区间存在P的循环右移,然后利用f[i][j]算一下第i个要到前n-1需要的最大的L,转移方程是g[i] = max(g[i-1],L)。
对于每个查询[L,R],只要判断L是不是比R大就可以知道[L,R]存不存在P的循环右移了。
AC代码:

#include<iostream>
using namespace std;
const int maxn = 2e5 + 50;
int pre[maxn];
int n,m,q;
int p[maxn],a[maxn],pos[maxn];
int f[maxn][21];
int g[maxn]; 
int sol(int x,int num){//利用f[i][j]计算x到前num个数需要的最大左端点
	for(int i = 20;i >= 0;--i){
		if((1<<i)&num) x = f[x][i];
	}return x;
}
int main(){
	cin>>n>>m>>q;
	for(int i = 1;i <= n;++i) scanf("%d",&p[i]),pre[p[i]] = p[i-1];
	pre[p[1]] = p[n];
	for(int i = 1;i <= m;++i){
		scanf("%d",&a[i]);
		pos[a[i]] = i;//记录a[i]这个数字最后一次出现的位置
		f[i][0] = pos[pre[a[i]]] ;//a[i]的第一个前驱的位置
		for(int j = 0;j < 20;++j) {
			f[i][j+1] = f[f[i][j]][j];
			//a[i]的第2^(j+1)个前驱是a[i]的第2^j个前驱的第2^j个前驱 
		}
		g[i] = max(g[i-1],sol(i,n-1));
	}
	while(q--){
		int l,r;scanf("%d%d",&l,&r);
		if(l<=g[r]) printf("1");
		else printf("0");
	}
} 
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值