CF1909F1 Small Permutation Problem (Easy Version) 题解

CF1909F1 Small Permutation Problem (Easy Version) 题解

直接莽做显然不好统计。考虑统计每一次 \(i\) 的变化有多少种方案数来匹配,也就是对 \(a\) 数组差分。

考虑到对于 \(a_i\),只有 \([1,i]\) 里的数会对 \(a_i\) 有影响。注意到 \(p\) 形成一个排列,于是我们不妨考虑此时 \(p\)\([1,i]\) 的贡献。

我们记 \(d=a_i-a_{i-1}\)

  • \(d=0\)\(p_i>i\)。此时 \([1,i]\) 中不变化,答案不变。
  • \(d=1\),可能是 \(i\) 这个数填在 \(1\sim i-1\) 中未填的位置上或 \([1,i]\) 中有数字填在位置 \(i\) 上。未填的位置有 \(i-1-a_{i-1}\) 个,剩余的数字还有 \(i-a_{i-1}\) 个,二者相加就是方案数系数。
  • \(d=2\),一定是 \(i\) 填在 \(1\sim i-1\) 未填的位置上或 \([1,i-1]\) 中有数字填在位置 \(i\) 上。于是方案数的系数就是 \((i-a_{i-1}-1)^2\)
  • \(d>2\),显然无解,输出 -1 即可。

注意加上一些不合法情况的特判即可。

代码:

#include <bits/stdc++.h>
#define N 200005
#define mod 998244353
#define int long long
using namespace std;
int T;
int n;
int a[N];
int solve() {
	if (a[1] > 1 || a[n] != n) return 0;
	int ans = 1;
	for (int i = 1; i <= n; i++) {
		int p = a[i] - a[i - 1];
		if (p == 0) continue;
		else if(p == 1) ans = ans * (i - a[i - 1] + i - 1 - a[i - 1]) % mod;
		else if(p == 2) ans = ans * (i - 1 - a[i - 1]) % mod * (i - 1 - a[i - 1]) % mod;
		else return 0;
	}
	return ans;
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> T;
	while (T--) {
		cin >> n;
		for (int i = 1; i <= n; i++)
			cin >> a[i];
		cout << solve() << "\n";
	}
	return 0;
}
posted @ 2024-11-15 22:00  长安19路  阅读(29)  评论(0)    收藏  举报