CF1142B,代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
const int LOG = 20; // 2^20 > 200000,足够覆盖所有情况
int n, m, q;
int p[MAXN], a[MAXN], pos[MAXN]; // pos记录每个数在排列p中的位置
int nxt[MAXN][LOG]; // 倍增数组:nxt[i][j]表示从位置i跳2^j步到达的位置
int last[MAXN]; // last[i]表示从位置i开始匹配一个完整循环移位后到达的位置
int st[MAXN][LOG], lg[MAXN]; // ST表相关数组
// ST表查询区间最小值
int query(int l, int r) {
int k = lg[r - l + 1];
return min(st[l][k], st[r - (1 << k) + 1][k]);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
// 读入数据
cin >> n >> m >> q;
for (int i = 1; i <= n; i++) {
cin >> p[i];
pos[p[i]] = i; // 记录每个数在排列p中的位置
}
for (int i = 1; i <= m; i++)
cin >> a[i];
// 预处理每个数在a中下一个出现的位置
// next_pos[x]记录数字x在a中下一个出现的位置,初始设为m+1(表示不存在)
vector<int> next_pos(n + 1, m + 1);
// 从后往前处理a数组,这样可以快速找到每个数后面最近的出现位置
for (int i = m; i >= 1; i--) {
int x = a[i]; // 当前数字
// 计算x在排列p中的下一个数字(考虑循环)
// 例如:如果p=[2,1,3],x=2在p中位置是1,下一个就是p[2]=1
// 如果x=3在p中位置是3,下一个就是p[1]=2(循环)
int next_val = p[pos[x] % n + 1];
// 记录从位置i跳1步(匹配下一个数字)到达的位置
nxt[i][0] = next_pos[next_val];
// 更新当前数字x的最新出现位置
next_pos[x] = i;
}
// 倍增预处理:计算跳2^j步到达的位置
for (int j = 1; j < LOG; j++)
for (int i = 1; i <= m; i++)
if (nxt[i][j-1] <= m)
// 从i跳2^(j-1)步到位置k,再从k跳2^(j-1)步
nxt[i][j] = nxt[nxt[i][j-1]][j-1];
else
nxt[i][j] = m + 1; // 超出范围
// 计算每个位置跳n-1步后到达的位置(匹配一个完整的循环移位)
for (int i = 1; i <= m; i++) {
int cur = i; // 当前位置
int steps = n - 1; // 需要跳的步数(匹配n个数字,第一个已经匹配,还需要n-1步)
// 二进制拆分:从高位到低位尝试跳步
for (int j = LOG - 1; j >= 0; j--) {
if (steps >= (1 << j)) {
steps -= (1 << j);
cur = nxt[cur][j];
if (cur > m) break; // 如果已经超出范围,提前结束
}
}
last[i] = cur; // 记录从位置i开始匹配完整循环移位后到达的位置
}
// 预处理ST表:用于快速查询区间最小值
// 预处理对数数组,用于ST表查询
lg[1] = 0;
for (int i = 2; i <= m; i++)
lg[i] = lg[i/2] + 1;
// 初始化ST表第一层
for (int i = 1; i <= m; i++)
st[i][0] = last[i];
// 构建ST表
for (int j = 1; j <= lg[m]; j++)
for (int i = 1; i + (1 << j) - 1 <= m; i++) {
st[i][j] = min(st[i][j-1], st[i + (1 << (j-1))][j-1]);
// 处理查询
string ans;
while (q--) {
int l, r;
cin >> l >> r;
// 查询[l, r]区间内last的最小值
// 如果最小值<=r,说明存在某个位置i∈[l,r],从i开始可以匹配一个完整的循环移位
// 且匹配结束的位置也在[l,r]范围内
if (query(l, r) <= r) {
ans += '1';
} else {
ans += '0';
}
}
cout << ans << '\n';
return 0;
}

17万+

被折叠的 条评论
为什么被折叠?



