CF1442B 确定操作

1 CF1442B 确定操作

2 题目描述

对一组数据 \(𝑎_1,𝑎_2,...,𝑎_𝑛\) 和空数组 \(𝑏\),我们应用下面的操作 \(𝑘\)次。
在第\(𝑖\)次操作中,我们选择一个坐标 \(𝑡_𝑖\)(1≤\(𝑡_𝑖\)≤𝑛−𝑖+1),从数组中删除 \(𝑎_𝑡\)\(_𝑖\),并将数字 \(𝑎_𝑡\)\(_𝑖\)\(_-\)\(_1\)$ 或 \(𝑎\)_𝑡$$𝑖$$+$$_1$$(如果 $$𝑎_𝑡$$𝑖$$-$$_1$$ 或 \(𝑎\)_𝑡$$𝑖$$+$$_1$ 在数组内)附加到数组 \(𝑏\) 的右端。 然后我们移动元素 \(𝑎_𝑡\)\(_𝑖\)\(_+\)\(_1\),...,\(𝑎_𝑛\) 填充到左边的闲置空间。

给出初始数据 \(𝑎_1\),\(𝑎_2\),...,\(𝑎_𝑛\) 和所产生的数组 \(𝑏_1\),\(𝑏_2\),...,\(𝑏_𝑘\)。数组 \(𝑏\) 的所有元素都不相同。计算 \(𝑡_1\),\(𝑡_2\),...,\(𝑡_𝑘\)\(998244353\) 的可能序列数。

3 解题思路

我们仔细分析,发现:如果一个数被选入了 \(b\) 数组,那么它在被选入 \(b\) 数组前没有被删除。转换一下,我们就可以得出:如果一个数被成功选入了,那么其左边或者右边的数肯定比它要先被选入\(b\)数组,因为这样删不删除它们都无所谓了。每个数能分裂出的方案数一定是其两旁的比这个数先选入 \(b\) 数组的数的个数。这是因为当左边的数比它先选入 \(b\) 数组时,左边的数在被选入后就把这个数选入,右侧同理。而最终的答案就是所有被选入\(b\)数组中的数分裂出的方案数之积。

但是有一个问题:如果当前数的旁边的数在被选入后就被删了,没来得及等到当前数被选入\(b\)数组的时刻。但是我们仔细一想:如果旁边的数在被选入后就被删了,那么它推举的数肯定比当前数被选入的时间早。这个时候,当前数就将魔爪伸向了这个新的数,把它作为旁边的数了。因此,答案的统计仍然是正确的。

最后提醒一句:别忘了取模!

4 代码(空格警告):

#include <iostream>
using namespace std;
const int N = 200005;
const int mod = 998244353;
int T, n, k, ans, cnt;
bool f[N];
int a[N], b[N], pos[N];
int main()
{
    cin >> T;
    while (T--)
    {
        ans = 1;
        cin >> n >> k;
        for (int i = 1; i <= n; i++) pos[i] = 0, f[i] = 0;
        for (int i = 1; i <= n; i++) cin >> a[i];
        for (int i = 1; i <= k; i++) cin >> b[i], pos[b[i]] = i, f[b[i]] = 1;
        for (int i = 1; i <= n; i++)
        {
            cnt = 0;
            if (i > 1 && pos[a[i-1]] < pos[a[i]]) cnt++;
            if (i < n && pos[a[i+1]] < pos[a[i]]) cnt++;
            if (f[a[i]]) ans = (ans * cnt) % mod;
        }
        cout << ans << endl;
    }
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-02-05 15:20  David24  阅读(56)  评论(0编辑  收藏  举报