Description
给定两个数组 \(a,b\),长度分别为 \(n,m( m \le n)\)。\(a\) 是 \(1..n\) 的全排列,\(b\) 是一个 \(1..n\) 的 \(m\) 排列。\(b\) 是目标序列,即我们需要通过以下的操作来构造一个答案序列使其等于 \(b\)。每次操作选择一个 \(t\),将 \(a_{t-1}\) 或 \(a_{t+1}\) 插入答案序列末尾并将 \(a_t\) 删除。问有多少种不同的构造方案。
Solution
考虑对于出现在 \(b\) 中的每一个 \(a_i\),我们必然要删除 \(a_{i-1}\) 和 \(a_{i+1}\) 中的至少一个。
设 \(f(a_i)\) 表示 \(a_i\) 在 \(b\) 中的出现位置。
如果 \(a_{i-1}\) 存在,并且 \(f(a_{i-1}) \le f(a_{i})\),那么我们称这个 \(a_{i-1}\) 对于 \(a_i\) 是合法的。\(a_{i+1}\) 同理。
对于 \(a_i\),有如下三种情况:
-
如果 \(a_{i-1},a_{i+1}\) 均合法,那么我们可以删除任意一个,方案数乘 \(2\)。之所以现在可以删除任意,是因为 \(a_{i-1},a_i,a_{i+1}\) 的出现位置必然都在 \(b\) 中后面所有数之前,因此他们并没有区别。
-
如果 \(a_{i-1},a_{i+1}\) 中恰好有一个合法,那么我们把它删除即可。
-
如果 \(a_{i-1},a_{i+1}\) 均不合法,则无解。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
const int N = 1000005;
struct Node
{
int val;
Node *prec = NULL;
Node *succ = NULL;
} node[N];
void deleteNode(Node *p)
{
if (p == NULL)
return;
Node *prec = p->prec;
Node *succ = p->succ;
p->prec = p->succ = NULL;
if (prec)
prec->succ = succ;
if (succ)
succ->prec = prec;
}
void deleteNode(Node &p)
{
deleteNode(&p);
}
int n, m, a[N], b[N], f[N], c[N];
void clearall(int n)
{
for (int i = 0; i <= n+1; i++)
a[i] = b[i] = f[i] = c[i] = node[i].val = 0,
node[i].prec = node[i].succ = 0;
}
void solve()
{
cin >> n >> m;
clearall(n);
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= m; i++)
cin >> b[i];
for (int i = 1; i <= m; i++)
f[b[i]] = i;
for (int i = 1; i <= n; i++)
node[i].val = a[i];
for (int i = 1; i <= n; i++)
node[i].prec = node[i].succ = NULL;
for (int i = 1; i < n; i++)
node[i].succ = &node[i + 1];
for (int i = 2; i <= n; i++)
node[i].prec = &node[i - 1];
for (int i = 1; i <= n; i++)
c[a[i]] = i;
int ans = 1;
for (int j = 1; j <= m; j++)
{
int i = c[b[j]];
Node *p = &node[i];
Node *prec = p->prec;
Node *succ = p->succ;
if (prec && f[prec->val] > j)
prec = NULL;
if (succ && f[succ->val] > j)
succ = NULL;
if (prec && succ)
{
ans *= 2;
ans %= mod;
deleteNode(prec);
}
else if (prec)
{
deleteNode(prec);
}
else if (succ)
{
deleteNode(succ);
}
else
{
cout << 0 << endl;
return;
}
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--)
{
solve();
}
}