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();
    }
}

相关文章:

  • 2022-12-23
  • 2021-08-26
  • 2022-12-23
  • 2021-10-07
  • 2021-10-09
  • 2021-05-20
  • 2021-05-08
猜你喜欢
  • 2021-09-20
  • 2021-11-07
  • 2021-04-08
  • 2021-11-03
  • 2022-12-23
  • 2021-08-13
  • 2022-12-23
相关资源
相似解决方案