洛谷P13788题解

分析

题意

给定两个长度均为 nn 的由 11nn 构成的排列 aabb。要求求出 aa 的非空连续子段中,有多少个是 bb 的子序列。

其中,aa 的连续子段是指从 aa 的开头和结尾各删除若干个元素(可能为 00 个)后得到的序列;bb 的子序列是指在 bb 中任意位置删除若干个元素(可能为 00 个)后得到的序列。

思路

一个序列 ccbb 的子序列,意味着 cc 中元素在 bb 中出现的顺序与 cc 中元素的顺序一致。对于 aa 的连续子段,若要成为 bb 的子序列,其对应元素在 bb 中的位置应是递增的。

首先,我们可以通过一个 pospos 数组记录 bb 中每个元素的位置,即 posxpos _x 表示元素 xxbb 中的位置。

然后定义 dpidp_i 表示以 aia_i 为结尾的 aa 的连续子段中是 bb 的子序列的数量。

当考虑 aia_i时,初始情况下 dpidp_i 至少为 11(即 aia_i 自身构成的子段)。

i>1i>1ai1a_{i-1}bb 中的位置 posai1pos_{a_{i-1}} 小于 aia_ibb 中的位置 posaipos_{a_i},说明以 ai1a_{i - 1} 为结尾的符合要求的子段可以和 aia_i 组成新的符合要求的子段,所以 dpi=dpi1+1dp_i = dp_{i-1} + 1

最后将所有的 dpidp_i 相加,得到的结果就是答案。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000005;
int a[MAXN], b[MAXN];
int pos[MAXN];
int dp[MAXN];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) {
cin >> b[i];
pos[b[i]] = i;
}
long long ans = 0;
for (int i = 1; i <= n; i++) {
int cur = pos[a[i]];
dp[i] = 1;
if (i > 1 && pos[a[i - 1]] < cur) {
dp[i] = dp[i - 1] + 1;
}
ans += dp[i];
}
cout << ans << endl;
return 0;
}

洛谷P13788题解
https://lijingshu2014.github.io/2025/10/03/洛谷P13788题解/
作者
lijingshu
发布于
2025年10月3日
许可协议