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